From abee6672efdff2214c85aba332dd73895296e52b Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Wed, 22 Feb 2012 11:01:36 +0800 Subject: NFC JNI: do not log the aid of the transaction For security reasons, the system must not log the aid of the transaction. Log the aid only if TRACE_ENABLED=1 for debugging purpose. Change-Id: I44b0918b534a216a56755090c9c9d83a58cda78c --- jni/com_android_nfc.h | 2 ++ jni/com_android_nfc_NativeNfcManager.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h index c757c7a..917b792 100644 --- a/jni/com_android_nfc.h +++ b/jni/com_android_nfc.h @@ -112,9 +112,11 @@ extern "C" { #if 0 #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); #define TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) + #define TRACE_ENABLED 1 #else #define LOG_CALLBACK(...) #define TRACE(...) + #define TRACE_ENABLED 0 #endif struct nfc_jni_native_data diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp index 4c46a0e..30b71a8 100644 --- a/jni/com_android_nfc_NativeNfcManager.cpp +++ b/jni/com_android_nfc_NativeNfcManager.cpp @@ -1248,13 +1248,14 @@ static void nfc_jni_transaction_callback(void *context, if(aid != NULL) { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + if (TRACE_ENABLED == 1) { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + LOGD("> AID: %s", aid_str); } - LOGD("> AID: %s", aid_str); - tmp_array = e->NewByteArray(aid->length); if (tmp_array == NULL) { -- cgit v1.1 From 7b669606dcd3efdb07d8b9ae2459580209d7d2e0 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Wed, 2 May 2012 11:47:29 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I69989c92c36a4b395abc531a229d2bc020b1b454 --- res/values-in/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index b8e6bb6..f83e7e4 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -3,8 +3,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "Layanan Nfc" "Nfc" - "Kenalan yang diterima lewat NFC" - "Sentuh untuk menambahkan orang ini sebagai kenalan." + "Kontak yang diterima lewat NFC" + "Sentuh untuk menambahkan orang ini sebagai kontak." "Interaksi NFC lengkap" "Sentuh untuk memberikan orang ini info kontak Anda." "NFC diaktifkan." -- cgit v1.1 From 14e80b44db846029373783a02bee0a8d97d92ea5 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 11 May 2012 12:42:35 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Iabc7546f56cd68daa446ab55886af1d2462c7ab1 --- res/values-af/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-am/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ar/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-be/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-bg/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ca/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-cs/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-da/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-de/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-el/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-en-rGB/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-es-rUS/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-es/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-et/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-fa/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-fi/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-fr/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-hi/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-hr/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-hu/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-in/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-it/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-iw/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ja/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ko/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-lt/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-lv/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ms/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-nb/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-nl/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-pl/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-pt-rPT/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-pt/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ro/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-ru/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-sk/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-sl/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-sr/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-sv/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-sw/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-th/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-tl/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-tr/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-uk/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-vi/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-zh-rCN/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-zh-rTW/strings.xml | 30 ++++++++++++++++++++++++++++++ res/values-zu/strings.xml | 30 ++++++++++++++++++++++++++++++ 48 files changed, 1440 insertions(+) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 1afb550..419d4bc 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -9,4 +9,34 @@ "Raak om aan hierdie persoon jou kontakinligting te gee." "NFC geaktiveer." "Raak en straal" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 23ea502..da4f52b 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -9,4 +9,34 @@ "ለዚህ ሰው የአንተን ዕውቅያ መረጃ ለመስጠት መታ አድርግ" "NFC ነቅቷል፡፡" "ለማብራት ንካ" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 9a7a0ee..4e1a92d 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -9,4 +9,34 @@ "المس لمنح هذا الشخص معلومات اتصالك." "تم تمكين NFC." "المس لرسم شعاع" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index f4f9b9a..6715d49 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -9,4 +9,34 @@ "Націсніце, каб даслаць гэтаму чалавеку сваю кантактн. інфармацыю" "NFC ўключаны." "Краніце, каб перадаць" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index ea376f6..e625c02 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -9,4 +9,34 @@ "Докоснете, за да дадете на този човек информацията си за връзка." "КБП е активирана." "Докоснете, за да излъчите" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 8cc2e27..2f8513d 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -9,4 +9,34 @@ "Toca per donar la teva informació de contacte a aquesta persona." "NFC activat." "Toca per fer brillar" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index b5c1a36..eba1955 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -9,4 +9,34 @@ "Klepnutím této osobě předáte své kontaktní informace." "Funkce NFC povolena." "Přenos zahájíte dotykem" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index bc0559d..37e15d3 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -9,4 +9,34 @@ "Tryk for at give denne person dine kontaktoplysninger." "NFC er aktiveret." "Tryk for at overføre" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index b8b6a1a..8f904cf 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -9,4 +9,34 @@ "Zum Weitergeben Ihrer Kontaktinformationen an diese Person tippen" "NFC aktiviert" "Zum Beamen berühren" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 1847a1d..e0142dc 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -9,4 +9,34 @@ "Αγγίξτε για να δώσετε σε αυτό το άτομο τα στοιχεία επικοινωνίας σας." "Ενεργοποίηση ΕΚΠ." "Αγγίξτε για μετάδοση" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 018832b..4e0a11b 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -9,4 +9,34 @@ "Touch to give this person your contact info." "NFC enabled." "Touch to beam" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 2c723cc..b66f732 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -9,4 +9,34 @@ "Toca para que esta persona obtenga tu información de contacto." "Se habilitó la NFC." "Tocar para transmitir" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index c5c3318..c8d6483 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -9,4 +9,34 @@ "Toca para compartir tu información de contacto con esta persona." "NFC habilitada" "Toca para compartir" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 56baa00..0bd947b 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -9,4 +9,34 @@ "Puudutage, et anda sellele inimesele oma kontaktandmed." "NFC lubatud." "Puudutage kiire kasutamiseks" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 10c84df..04539b1 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -9,4 +9,34 @@ "لمس کنید تا اطلاعات تماس خود را به این فرد بدهید." "با NFC فعال شده." "برای پخش، لمس کنید" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 94ead99..214bad1 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -9,4 +9,34 @@ "Anna tälle henkilölle yhteystietosi koskettamalla." "NFC otettu käyttöön." "Kosketa palkkia" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index a81f248..428b9d6 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -9,4 +9,34 @@ "Appuyez pour communiquer vos coordonnées à cette personne." "NFC activée" "Appuyer pour partager" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 368999a..1846cab 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -9,4 +9,34 @@ "इस व्‍यक्ति को अपनी संपर्क जानकारी देने के लिए स्‍पर्श करें." "NFC सक्षम है." "बीम करने के लिए स्पर्श करें" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 89d4547..b5791ad 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -9,4 +9,34 @@ "Dodirnite kako biste ovoj osobi dali svoje podatke za kontakt." "NFC omogućen." "Dodirnite za emitiranje" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 97d501a..e17f973 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -9,4 +9,34 @@ "Érintse meg kapcsolatfelvételi adatok megosztásához." "NFC bekapcsolva" "Érintse meg a sugárzáshoz" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index f83e7e4..c161448 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -9,4 +9,34 @@ "Sentuh untuk memberikan orang ini info kontak Anda." "NFC diaktifkan." "Sentuh untuk menyorot" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index a790a18..551da14 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -9,4 +9,34 @@ "Tocca per inviare a questa persona le informazioni di contatto" "Comunicazione NFC abilitata." "Tocca per trasmettere" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 6751dbd..4fe50ca 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -9,4 +9,34 @@ "גע כדי לתת למשתמש זה את פרטי הקשר שלך" "NFC מופעל." "גע כדי להקרין" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 0574e36..0b1466a 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -9,4 +9,34 @@ "このユーザーに連絡先情報を提供するにはタッチします。" "NFCは有効です。" "タップしてビーム" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 45cc68d..9cb341f 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -9,4 +9,34 @@ "이 사람에게 내 연락처 정보를 제공하려면 터치하세요." "NFC 사용" "공유하기" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 64b09d5..df9294f 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -9,4 +9,34 @@ "Palieskite, kad šiam asmeniui suteiktumėte savo kontakt. inf." "ALR įgalinta." "Jei norite perduoti, palieskite" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 4ae0c7d..84334e9 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -9,4 +9,34 @@ "Pieskarieties, lai sniegtu šai personai savu kontaktinformāciju." "NFC ir iespējoti." "Pieskarties, lai projicētu" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index afaf398..f0984a6 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -9,4 +9,34 @@ "Sentuh untuk memberi orang ini maklumat hubungan anda." "NFC didayakan." "Sentuh untuk memancarkan" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 58656c2..ec9ae5a 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -9,4 +9,34 @@ "Berør for å gi denne personen kontaktinformasjonen din." "NFC er aktivert." "Berør for å overføre trådløst" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index c055d2a..c5d57f0 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -9,4 +9,34 @@ "Raak aan om deze persoon uw contactgegevens te geven." "NFC ingeschakeld." "Tikken om uit te zenden" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 68a895c..55f56b2 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -9,4 +9,34 @@ "Dotknij, aby przekazać tej osobie swoje dane kontaktowe." "Komunikacja NFC włączona." "Dotknij, aby przesłać" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 928e9f4..d00c09e 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -9,4 +9,34 @@ "Toque para dar a esta pessoa as suas informações de contacto." "NFC ativado." "Toque para transmitir" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 7b6817d..77040d3 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -9,4 +9,34 @@ "Toque para fornecer suas informações de contato para essa pessoa" "NFC habilitado." "Toque para iluminar" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 7943369..7888de7 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -9,4 +9,34 @@ "Atingeţi pentru a oferi acestei persoane datele dvs. de contact" "NFC activat." "Atingeţi pentru transmitere" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 712222c..7b6f569 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -9,4 +9,34 @@ "Нажмите, чтобы передать свои контактные данные." "Служба NFC включена" "Нажмите, чтобы передать данные" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index a9d18ea..b149c6d 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -9,4 +9,34 @@ "Dotknutím sa tejto osobe odovzdáte svoje kontaktné informácie." "NFC povolené." "Dotykom spustíte prenos" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 3aabe24..ef8e47d 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -9,4 +9,34 @@ "Tapnite, če želite tej osebi poslati svoje podatke za stik." "NFC omogočen." "Dotaknite se, da pošljete" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 752ab20..7f28427 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -9,4 +9,34 @@ "Додирните да бисте овој особи дали контакт информације." "NFC је омогућен." "Додирните за емитовање" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 3a91cab..52e61ce 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -9,4 +9,34 @@ "Tryck om du vill ge personen dina kontaktuppgifter." "NFC aktiverat." "Tryck här om du vill överföra" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index d8058f9..95fb4a2 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -9,4 +9,34 @@ "Gusa ili kumpa mtu huyu maelezo yako ya mawasiliano." "NFC imewezeshwa." "Gusa kwa boriti" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index bd8693b..e0e2113 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -9,4 +9,34 @@ "แตะเพื่อให้ข้อมูลที่อยู่ติดต่อของคุณแก่คนนี้" "เปิดใช้งาน NFC แล้ว" "แตะเพื่อส่ง" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 1f55bfe..9f0bdcf 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -9,4 +9,34 @@ "Pindutin para ibigay sa taong ito ang impormasyon ng contact mo" "Pinagana ang NFC." "Pindutin upang i-beam" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 9796c9f..683af8e 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -9,4 +9,34 @@ "Bu kullanıcıya kişi bilgilerinizi vermek için dokunun." "NFC etkin." "Göndermek için dokunun" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index dcca06a..98c0e1e 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -9,4 +9,34 @@ "Торкніться, щоб надати цій особі свою контактну інформацію." "NFC увімкнено." "Торкніться, щоб передати дані" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index e41b67b..51d1818 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -9,4 +9,34 @@ "Chạm để gửi cho người này thông tin liên hệ của bạn." "Đã bật NFC." "Chạm để truyền" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 2a0d1ae..0f05e1f 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -9,4 +9,34 @@ "接触可向此人发送您的联系人信息。" "NFC 已启用。" "触摸即可发送" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 41707b1..16438e6 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -9,4 +9,34 @@ "輕觸即可將您的聯絡人資訊傳送給這位使用者。" "NFC 已啟用。" "輕觸即可傳輸" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 4582285..282f37b 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -9,4 +9,34 @@ "Thinta ukuze unike lomuntu imininingwane yakho yokuxhumana" "I-NFC ivunyelwe." "Cindezela kwibhimu" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.1 From 58ead98396fa07770893bcc0d8ed5585464d65f5 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Mon, 14 May 2012 11:58:39 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I24bbc1d87e74784c9683d2f612de043e30eaea34 --- res/values-af/strings.xml | 45 +++++++++++++++---------------------------- res/values-am/strings.xml | 45 +++++++++++++++---------------------------- res/values-be/strings.xml | 45 +++++++++++++++---------------------------- res/values-cs/strings.xml | 45 +++++++++++++++---------------------------- res/values-da/strings.xml | 45 +++++++++++++++---------------------------- res/values-de/strings.xml | 45 +++++++++++++++---------------------------- res/values-el/strings.xml | 45 +++++++++++++++---------------------------- res/values-en-rGB/strings.xml | 45 +++++++++++++++---------------------------- res/values-es-rUS/strings.xml | 45 +++++++++++++++---------------------------- res/values-fr/strings.xml | 45 +++++++++++++++---------------------------- res/values-hu/strings.xml | 45 +++++++++++++++---------------------------- res/values-in/strings.xml | 45 +++++++++++++++---------------------------- res/values-it/strings.xml | 45 +++++++++++++++---------------------------- res/values-iw/strings.xml | 45 +++++++++++++++---------------------------- res/values-pt/strings.xml | 45 +++++++++++++++---------------------------- res/values-uk/strings.xml | 45 +++++++++++++++---------------------------- res/values-zu/strings.xml | 45 +++++++++++++++---------------------------- 17 files changed, 255 insertions(+), 510 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 419d4bc..8b5638e 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -9,34 +9,19 @@ "Raak om aan hierdie persoon jou kontakinligting te gee." "NFC geaktiveer." "Raak en straal" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Straling aan die gang" + "Straling voltooi" + "Straling het misluk" + "Raak om te bekyk" + "Koppel tans" + "Gekoppel" + "Kon nie verbind nie" + "Ontkoppel tans" + "Ontkoppel" + "Saambinding" + "Kon nie saambind nie" + "Kon nie Bluetooth aktiveer nie" + "Is jy seker jy wil die Bluetooth-toestel, %1$s, saambind?" + "Ja" + "Nee" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index da4f52b..14d1e1d 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -9,34 +9,19 @@ "ለዚህ ሰው የአንተን ዕውቅያ መረጃ ለመስጠት መታ አድርግ" "NFC ነቅቷል፡፡" "ለማብራት ንካ" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "ሞገድ በሂደት ላይ" + "ሞገድ ተጠናቅቋል" + "ሞገድ አልተሳካም" + "ለማየት ንካ" + "በመገናኘት ላይ" + "ተገናኝቷል" + "መገናኘት አልተሳካም" + "ግንኙነት በማቋረጥ ላይ" + "ግንኙነት ተቋርጧል" + "በማጣመር ላይ" + "ማጣመር አልተሳካም" + "ብሉቱዝ ማንቃት አልተሳካም" + "እርግጠኛ ነህ የብሉቱዝ መሣሪያው %1$sን ማጣመር ትፈልጋለህ?" + "አዎ" + "የለም" diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 6715d49..9c68149 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -9,34 +9,19 @@ "Націсніце, каб даслаць гэтаму чалавеку сваю кантактн. інфармацыю" "NFC ўключаны." "Краніце, каб перадаць" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Ідзе працэс перадачы Beam" + "Працэс перадачы Beam завершаны" + "Няўдалы працэс перадачы Beam" + "Націсніце, каб прагледзець" + "Падключэнне" + "Падключана" + "Не атрымалася падключыцца" + "Адключэнне" + "Адключана" + "Падлучэнне" + "Не атрымалася выканаць падлучэнне" + "Не атрымалася ўключыць Bluetooth" + "Вы ўпэўнены, што жадаеце падлучыць прыладу Bluetooth %1$s?" + "Так" + "Не" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index eba1955..17f43d5 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -9,34 +9,19 @@ "Klepnutím této osobě předáte své kontaktní informace." "Funkce NFC povolena." "Přenos zahájíte dotykem" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Probíhá přenos" + "Přenos dokončen" + "Přenos se nezdařil" + "Zobrazte dotykem" + "Připojování" + "Připojeno" + "Připojení se nezdařilo" + "Odpojování" + "Odpojeno" + "Párování" + "Párování se nezdařilo" + "Aktivace Bluetooth se nezdařila" + "Opravdu chcete spárovat zařízení Bluetooth %1$s?" + "Ano" + "Ne" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 37e15d3..a032d09 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -9,34 +9,19 @@ "Tryk for at give denne person dine kontaktoplysninger." "NFC er aktiveret." "Tryk for at overføre" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Overførsel i gang" + "Overførsel fuldført" + "Overførslen mislykkedes" + "Tryk for at få vist" + "Opretter forbindelse" + "Forbundet" + "Der kunne ikke oprettes forbindelse" + "Afbryder forbindelse" + "Afbrudt" + "Parrer" + "Kunne ikke parres" + "Bluetooth kunne ikke aktiveres" + "Er du sikker på du vil parre Bluetooth-enheden %1$s?" + "Ja" + "Nej" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 8f904cf..629620f 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -9,34 +9,19 @@ "Zum Weitergeben Ihrer Kontaktinformationen an diese Person tippen" "NFC aktiviert" "Zum Beamen berühren" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Beamen läuft" + "Beamen abgeschlossen" + "Fehler beim Beamen" + "Zum Ansehen berühren" + "Verbindung wird hergestellt" + "Verbunden" + "Verbindung konnte nicht aufgebaut werden." + "Verbindung wird aufgehoben" + "Verbindung getrennt" + "Pairing erfolgt" + "Fehler beim Pairing" + "Bluetooth konnte nicht aktiviert werden." + "Möchten Sie das Bluetooth-Gerät %1$s wirklich koppeln?" + "Ja" + "Nein" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index e0142dc..7e8ab8a 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -9,34 +9,19 @@ "Αγγίξτε για να δώσετε σε αυτό το άτομο τα στοιχεία επικοινωνίας σας." "Ενεργοποίηση ΕΚΠ." "Αγγίξτε για μετάδοση" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Η ζεύξη βρίσκεται σε εξέλιξη" + "Ολοκλήρωση ζεύξης" + "Αποτυχία ζεύξης" + "Αγγίξτε για προβολή" + "Σύνδεση" + "Συνδέθηκε" + "Αποτυχία σύνδεσης" + "Αποσύνδεση" + "Σε αποσύνδεση" + "Σύζευξη" + "Αποτυχία σύζευξης" + "Αποτυχία ενεργοποίησης του Bluetooth" + "Είστε βέβαιοι ότι θέλετε να γίνει σύζευξη της συσκευής Bluetooth %1$s;" + "Ναι" + "Όχι" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 4e0a11b..eb665aa 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -9,34 +9,19 @@ "Touch to give this person your contact info." "NFC enabled." "Touch to beam" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Beam in progress" + "Beam complete" + "Beam failed" + "Touch to view" + "Connecting..." + "Connected" + "Failed to connect" + "Disconnecting" + "Disconnected" + "Pairing" + "Failed to pair" + "Failed to enable Bluetooth" + "Are you sure you want to pair the Bluetooth device %1$s?" + "Yes" + "No" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index b66f732..9cb7ac1 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -9,34 +9,19 @@ "Toca para que esta persona obtenga tu información de contacto." "Se habilitó la NFC." "Tocar para transmitir" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Transmisión en curso" + "Transmisión completa" + "Se produjo un error al transmitir el contenido." + "Toca para ver" + "Conectando..." + "Conectados" + "Se produjo un error al establecer conexión." + "Desconectando..." + "Desconectados" + "Sincronización" + "Se produjo un error al establecer la sincronización." + "Se produjo un error al activar Bluetooth." + "¿Realmente deseas sincronizar el dispositivo Bluetooth %1$s?" + "Sí" + "No" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 428b9d6..569fc68 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -9,34 +9,19 @@ "Appuyez pour communiquer vos coordonnées à cette personne." "NFC activée" "Appuyer pour partager" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Partage en cours…" + "Partage terminé." + "Échec du partage." + "Appuyer pour afficher" + "Connexion en cours…" + "Connecté" + "Échec de la connexion." + "Déconnexion en cours…" + "Déconnecté" + "Association en cours…" + "Échec de l\'association." + "Échec de l\'activation du Bluetooth." + "Voulez-vous vraiment associer l\'appareil Bluetooth %1$s ?" + "Oui" + "Non" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index e17f973..e306bb8 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -9,34 +9,19 @@ "Érintse meg kapcsolatfelvételi adatok megosztásához." "NFC bekapcsolva" "Érintse meg a sugárzáshoz" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Átvitel folyamatban." + "Átvitel befejezve." + "Átvitel sikertelen." + "A megtekintéshez érintse meg." + "Csatlakozás" + "Csatlakozva" + "Sikertelen csatlakozás." + "Szétkapcsolás" + "Szétkapcsolva" + "Párosítás" + "Nem sikerült párosítani." + "Nem sikerült bekapcsolni a Bluetootht." + "Biztosan párosítani szeretné a(z) %1$s Bluetooth-eszközt?" + "Igen" + "Nem" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index c161448..a82e1c1 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -9,34 +9,19 @@ "Sentuh untuk memberikan orang ini info kontak Anda." "NFC diaktifkan." "Sentuh untuk menyorot" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Beam sedang berlangsung" + "Beam selesai" + "Beam gagal" + "Sentuh untuk melihat" + "Menyambungkan" + "Tersambung" + "Gagal menyambungkan" + "Memutuskan" + "Terputus" + "Menyandingkan" + "Gagal menyandingkan" + "Gagal mengaktifkan Bluetooth" + "Yakin ingin menyandingkan perangkat Bluetooth %1$s?" + "Ya" + "Tidak" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 551da14..eb3c77f 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -9,34 +9,19 @@ "Tocca per inviare a questa persona le informazioni di contatto" "Comunicazione NFC abilitata." "Tocca per trasmettere" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Trasmissione in corso" + "Trasmissione completata" + "Trasmissione non riuscita" + "Tocca per visualizzare" + "Collegamento in corso" + "Collegato" + "Errore di connessione" + "Scollegamento in corso" + "Scollegato" + "Accoppiamento" + "Impossibile accoppiare" + "Impossibile attivare il Bluetooth" + "Vuoi accoppiare il dispositivo Bluetooth %1$s?" + "Sì" + "No" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 4fe50ca..0f50aa3 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -9,34 +9,19 @@ "גע כדי לתת למשתמש זה את פרטי הקשר שלך" "NFC מופעל." "גע כדי להקרין" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "הקרנה מתבצעת" + "הקרנה הושלמה" + "הקרנה נכשלה" + "גע כדי להציג" + "מתחבר" + "מחובר" + "ההתחברות נכשלה" + "מתנתק" + "מנותק" + "התאמה" + "ההתאמה נכשלה" + "הפעלת Bluetooth נכשלה" + "האם אתה בטוח שאתה רוצה להתאים את מכשיר ה-Bluetooth %1$s?" + "כן" + "לא" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 77040d3..54c214d 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -9,34 +9,19 @@ "Toque para fornecer suas informações de contato para essa pessoa" "NFC habilitado." "Toque para iluminar" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Irradiação em andamento" + "Irradiação concluída" + "Falha na irradiação" + "Toque para visualizar" + "Conectando" + "Conectado" + "Falha ao conectar" + "Desconectando" + "Desconectado" + "Pareando" + "Falha no pareamento" + "Falha ao ativar o Bluetooth" + "Tem certeza de que deseja parear o dispositivo Bluetooth %1$s?" + "Sim" + "Não" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 98c0e1e..b7b9a25 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -9,34 +9,19 @@ "Торкніться, щоб надати цій особі свою контактну інформацію." "NFC увімкнено." "Торкніться, щоб передати дані" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Виконується передавання даних" + "Передавання даних виконано" + "Передавання даних не виконано" + "Торкніться, щоб переглянути" + "Під’єднання" + "Під’єднано" + "Не вдалося під’єднатися" + "Від’єднання" + "Від’єднано" + "Створення пари" + "Не вдалося створити пару" + "Не вдалося ввімкнути Bluetooth" + "Дійсно створити пару з пристроєм Bluetooth %1$s?" + "Так" + "Ні" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 282f37b..b841678 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -9,34 +9,19 @@ "Thinta ukuze unike lomuntu imininingwane yakho yokuxhumana" "I-NFC ivunyelwe." "Cindezela kwibhimu" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "I-Beam iyaqhubeka" + "I-Beam iqedile" + "I-Beam yehlulekile" + "Thinta ukuze ubuke" + "Iyaxhuma" + "Ixhunyiwe" + "Yehlulekile ukuxhuma" + "Iyanqamula" + "Inqamukile" + "Iyabhangqa" + "Yehlulekile ukubhanqa" + "Yehlulekile ukunika amandla i-Bluetooth" + "Ingabe unesiqinisekiso sokuthi ufuna ukuhambisa ngakubili idivayisi %1$s ye-Bluetooth?" + "Yebo" + "Cha" -- cgit v1.1 From a5df0de4f222b6b4cae70f6c6701adc0904e2241 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Tue, 15 May 2012 16:00:44 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I3eb819bf8466dcbe0b0105de1f327d89f6b75406 --- res/values-bg/strings.xml | 45 +++++++++++++++---------------------------- res/values-es/strings.xml | 45 +++++++++++++++---------------------------- res/values-et/strings.xml | 45 +++++++++++++++---------------------------- res/values-fi/strings.xml | 45 +++++++++++++++---------------------------- res/values-hi/strings.xml | 45 +++++++++++++++---------------------------- res/values-hr/strings.xml | 45 +++++++++++++++---------------------------- res/values-ms/strings.xml | 45 +++++++++++++++---------------------------- res/values-ru/strings.xml | 45 +++++++++++++++---------------------------- res/values-sw/strings.xml | 45 +++++++++++++++---------------------------- res/values-zh-rCN/strings.xml | 45 +++++++++++++++---------------------------- res/values-zh-rTW/strings.xml | 45 +++++++++++++++---------------------------- 11 files changed, 165 insertions(+), 330 deletions(-) diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index e625c02..0d8f13c 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -9,34 +9,19 @@ "Докоснете, за да дадете на този човек информацията си за връзка." "КБП е активирана." "Докоснете, за да излъчите" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Излъчването е в ход" + "Излъчването завърши" + "Излъчването не бе успешно" + "Докоснете, за да видите" + "Свързва се" + "Има връзка" + "Свързването не бе успешно" + "Изключва се" + "Изключено" + "Извършва се сдвояване" + "Сдвояването не бе успешно" + "Активирането на Bluetooth не бе успешно" + "Наистина ли искате да сдвоите устройството с Bluetooth %1$s?" + "Да" + "Не" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index c8d6483..c5f5b4c 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -9,34 +9,19 @@ "Toca para compartir tu información de contacto con esta persona." "NFC habilitada" "Toca para compartir" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Transferencia en curso" + "Transferencia completada" + "Error al transferir contenido" + "Tocar para ver" + "Conectando..." + "Conectado" + "Error de conexión" + "Desconectando..." + "Desconectado" + "Sincronizando..." + "Error de sincronización" + "Error al habilitar Bluetooth" + "¿Seguro que quieres sincronizar el dispositivo Bluetooth %1$s?" + "Sí" + "No" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 0bd947b..4dabd05 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -9,34 +9,19 @@ "Puudutage, et anda sellele inimesele oma kontaktandmed." "NFC lubatud." "Puudutage kiire kasutamiseks" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Kiir on pooleli" + "Kiir on valmis" + "Kiir ebaõnnestus" + "Puudutage vaatamiseks" + "Ühendamine" + "Ühendatud" + "Ühendamine ebaõnnestus" + "Ühenduse katkestamine" + "Ühendus on katkestatud" + "Ühildamine" + "Ühildamine ebaõnnestus" + "Bluetoothi lubamine ebaõnnestus" + "Kas soovite kindlasti ühildada Bluetoothi seadme %1$s?" + "Jah" + "Ei" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 214bad1..b6abbf8 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -9,34 +9,19 @@ "Anna tälle henkilölle yhteystietosi koskettamalla." "NFC otettu käyttöön." "Kosketa palkkia" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Sisällön jako käynnissä" + "Sisältö jaettu" + "Sisällön jako epäonnistui" + "Kosketa ja näytä" + "Yhdistetään" + "Yhdistetty" + "Yhteyden muodostaminen epäonnistui" + "Katkaistaan yhteyttä" + "Yhteys katkaistu" + "Laiteparia muodostetaan" + "Laiteparin muodostus epäonnistui" + "Bluetoothin käyttöön ottaminen epäonnistui" + "Oletko varma, että haluat muodostaa laiteparin Bluetooth-laitteeseen %1$s?" + "Kyllä" + "Ei" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 1846cab..dd74683 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -9,34 +9,19 @@ "इस व्‍यक्ति को अपनी संपर्क जानकारी देने के लिए स्‍पर्श करें." "NFC सक्षम है." "बीम करने के लिए स्पर्श करें" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "बीम चल रहा है" + "बीम करना पूर्ण" + "बीम करना विफल रहा" + "देखने के लिए स्‍पर्श करें" + "कनेक्ट हो रहा है" + "कनेक्ट है" + "जोड़ने में विफल रहा" + "डिस्कनेक्ट कर रहा है" + "डिस्कनेक्ट किया गया" + "युग्मन" + "युग्मित करने में विफल रहा" + "Bluetooth सक्षम करने में विफल रहा" + "क्‍या आप वाकई Bluetooth उपकरण %1$s को युग्मित करना चाहते हैं?" + "हां" + "नहीं" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index b5791ad..57b12c5 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -9,34 +9,19 @@ "Dodirnite kako biste ovoj osobi dali svoje podatke za kontakt." "NFC omogućen." "Dodirnite za emitiranje" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Emitiranje u tijeku" + "Emitiranje je završeno" + "Emitiranje nije uspjelo" + "Dodirnite za prikaz" + "Povezivanje" + "Povezan" + "Povezivanje nije uspjelo" + "Prekid veze" + "Prekinuta veza" + "Uparivanje" + "Uparivanje nije uspjelo" + "Omogućavanje Bluetootha nije uspjelo" + "Jeste li sigurni da želite upariti Bluetooth uređaj %1$s?" + "Da" + "Ne" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index f0984a6..bdeb342 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -9,34 +9,19 @@ "Sentuh untuk memberi orang ini maklumat hubungan anda." "NFC didayakan." "Sentuh untuk memancarkan" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Pancar sedang berjalan" + "Pancar selesai" + "Pancar gagal" + "Sentuh untuk melihat" + "Menyambung" + "Disambungkan" + "Gagal menyambung" + "Memutuskan sambungan" + "Diputuskan sambungan" + "Menjadikan pasangan" + "Gagal untuk berpasangan" + "Gagal untuk mendayakan Bluetooth" + "Adakah anda pasti anda mahu memadankan peranti Bluetooth %1$s?" + "Ya" + "Tidak" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 7b6f569..a142798 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -9,34 +9,19 @@ "Нажмите, чтобы передать свои контактные данные." "Служба NFC включена" "Нажмите, чтобы передать данные" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Передача данных…" + "Передача данных завершена" + "Не удалось передать данные" + "Нажмите, чтобы просмотреть" + "Подключение…" + "Подключено" + "Сбой соединения" + "Отключение…" + "Отключено" + "Подключение…" + "Ошибка подключения" + "Не удалось включить Bluetooth" + "Подключить Bluetooth-устройство %1$s?" + "Да" + "Нет" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 95fb4a2..07a72c5 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -9,34 +9,19 @@ "Gusa ili kumpa mtu huyu maelezo yako ya mawasiliano." "NFC imewezeshwa." "Gusa kwa boriti" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "Boriti inaendelea" + "Boriti umekamilika" + "Boriti alishindwa" + "Gusa ili utazame" + "Inaunganisha" + "Imeunganishwa" + "Haikuweza kuunganisha." + "Inakata muunganisho..." + "Imekata muunganisho" + "Inalinganisha" + "Imeshindwa kulinganisha" + "Imeshindwa kuwawezesha Bluetooth" + "Una uhakika unataka kuunganisha kifaa chako chathe Bluetooth cha %1$s?" + "Ndiyo" + "Hapana" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 0f05e1f..cbdba1e 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -9,34 +9,19 @@ "接触可向此人发送您的联系人信息。" "NFC 已启用。" "触摸即可发送" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "正在发送" + "发送完毕" + "发送失败" + "触摸即可查看" + "正在连接" + "已连接" + "无法连接" + "正在断开连接" + "已断开连接" + "正在配对" + "无法配对" + "无法启用蓝牙" + "您确定要与蓝牙设备%1$s配对吗?" + "是" + "否" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 16438e6..afcbdfa 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -9,34 +9,19 @@ "輕觸即可將您的聯絡人資訊傳送給這位使用者。" "NFC 已啟用。" "輕觸即可傳輸" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + "傳輸中" + "傳輸完成" + "傳輸失敗" + "輕觸即可查看" + "連線中" + "已連線" + "無法連線" + "正在中斷連線" + "已中斷連線" + "配對中" + "無法配對" + "無法啟用藍牙功能" + "您確定要與藍牙裝置「%1$s」配對嗎?" + "是" + "否" -- cgit v1.1 From c989f25d17aca3e8001092c42684244222940330 Mon Sep 17 00:00:00 2001 From: Justin Koh Date: Thu, 17 May 2012 10:58:28 -0700 Subject: Don't instantiate sendUi in Nfc if we are in appliance mode. Don't initiate sendUi in Nfc if we are in appliance mode. This saves 20MB of memory. Bug: 6470917 TESTED = runs on Tungsten. Change-Id: I41df65a67cd0f3af3e73469c1679d707c98cc3f8 --- src/com/android/nfc/P2pEventManager.java | 53 ++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/com/android/nfc/P2pEventManager.java b/src/com/android/nfc/P2pEventManager.java index 8e4165d..c559ad2 100644 --- a/src/com/android/nfc/P2pEventManager.java +++ b/src/com/android/nfc/P2pEventManager.java @@ -54,7 +54,16 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { Context.NOTIFICATION_SERVICE); mSending = false; - mSendUi = new SendUi(context, this); + final int uiModeType = mContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_TYPE_MASK; + if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) { + // "Appliances" don't intrinsically have a way of confirming this, so we + // don't use the UI and just autoconfirm where necessary. + // Don't instantiate SendUi or else we'll use memory and never reclaim it. + mSendUi = null; + } else { + mSendUi = new SendUi(context, this); + } } @Override @@ -64,19 +73,17 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { mNdefReceived = false; mVibrator.vibrate(VIBRATION_PATTERN, -1); - mSendUi.takeScreenshot(); + if (mSendUi != null) { + mSendUi.takeScreenshot(); + } } @Override public void onP2pSendConfirmationRequested() { - final int uiModeType = mContext.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_TYPE_MASK; - if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) { - // "Appliances" don't intrinsically have a way of confirming this, so we - // will just auto-confirm. - mCallback.onP2pSendConfirmed(); - } else { + if (mSendUi != null) { mSendUi.showPreSend(); + } else { + mCallback.onP2pSendConfirmed(); } } @@ -84,7 +91,9 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { public void onP2pSendComplete() { mNfcService.playSound(NfcService.SOUND_END); mVibrator.vibrate(VIBRATION_PATTERN, -1); - mSendUi.showPostSend(); + if (mSendUi != null) { + mSendUi.showPostSend(); + } mSending = false; mNdefSent = true; } @@ -93,14 +102,16 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { public void onP2pReceiveComplete() { mVibrator.vibrate(VIBRATION_PATTERN, -1); mNfcService.playSound(NfcService.SOUND_END); - // TODO we still don't have a nice receive solution - // The sanest solution right now is just to scale back up what we had - // and start the new activity. It is not perfect, but at least it is - // consistent behavior. All other variants involve making the old - // activity screenshot disappear, and then removing the animation - // window hoping the new activity has started by then. This just goes - // wrong too often and can looks weird. - mSendUi.finish(SendUi.FINISH_SCALE_UP); + if (mSendUi != null) { + // TODO we still don't have a nice receive solution + // The sanest solution right now is just to scale back up what we had + // and start the new activity. It is not perfect, but at least it is + // consistent behavior. All other variants involve making the old + // activity screenshot disappear, and then removing the animation + // window hoping the new activity has started by then. This just goes + // wrong too often and can looks weird. + mSendUi.finish(SendUi.FINISH_SCALE_UP); + } mNdefReceived = true; } @@ -110,7 +121,7 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { mNfcService.playSound(NfcService.SOUND_ERROR); mSending = false; } - if (!mNdefSent && !mNdefReceived) { + if (!mNdefSent && !mNdefReceived && mSendUi != null) { mSendUi.finish(SendUi.FINISH_SCALE_UP); } } @@ -118,7 +129,9 @@ public class P2pEventManager implements P2pEventListener, SendUi.Callback { @Override public void onSendConfirmed() { if (!mSending) { - mSendUi.showStartSend(); + if (mSendUi != null) { + mSendUi.showStartSend(); + } mCallback.onP2pSendConfirmed(); } mSending = true; -- cgit v1.1 From ff99548437970ad22c1492b6ab8dd87aa2b73cba Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 25 May 2012 11:58:26 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I13f22b25fc0348613aae6f5cc7b11ca635869ec2 --- res/values-af/strings.xml | 18 +++++++++++++----- res/values-am/strings.xml | 20 ++++++++++++++------ res/values-ar/strings.xml | 41 +++++++++++++++++------------------------ res/values-be/strings.xml | 18 +++++++++++++----- res/values-bg/strings.xml | 18 +++++++++++++----- res/values-ca/strings.xml | 41 +++++++++++++++++------------------------ res/values-cs/strings.xml | 18 +++++++++++++----- res/values-da/strings.xml | 20 ++++++++++++++------ res/values-de/strings.xml | 20 ++++++++++++++------ res/values-el/strings.xml | 18 +++++++++++++----- res/values-en-rGB/strings.xml | 18 +++++++++++++----- res/values-es-rUS/strings.xml | 20 ++++++++++++++------ res/values-es/strings.xml | 18 +++++++++++++----- res/values-et/strings.xml | 18 +++++++++++++----- res/values-fa/strings.xml | 41 +++++++++++++++++------------------------ res/values-fi/strings.xml | 18 +++++++++++++----- res/values-fr/strings.xml | 18 +++++++++++++----- res/values-hi/strings.xml | 18 +++++++++++++----- res/values-hr/strings.xml | 18 +++++++++++++----- res/values-hu/strings.xml | 18 +++++++++++++----- res/values-in/strings.xml | 18 +++++++++++++----- res/values-it/strings.xml | 18 +++++++++++++----- res/values-iw/strings.xml | 18 +++++++++++++----- res/values-ja/strings.xml | 41 +++++++++++++++++------------------------ res/values-ko/strings.xml | 41 +++++++++++++++++------------------------ res/values-lt/strings.xml | 41 +++++++++++++++++------------------------ res/values-lv/strings.xml | 41 +++++++++++++++++------------------------ res/values-ms/strings.xml | 18 +++++++++++++----- res/values-nb/strings.xml | 41 +++++++++++++++++------------------------ res/values-nl/strings.xml | 41 +++++++++++++++++------------------------ res/values-pl/strings.xml | 41 +++++++++++++++++------------------------ res/values-pt-rPT/strings.xml | 41 +++++++++++++++++------------------------ res/values-pt/strings.xml | 18 +++++++++++++----- res/values-ro/strings.xml | 41 +++++++++++++++++------------------------ res/values-ru/strings.xml | 18 +++++++++++++----- res/values-sk/strings.xml | 41 +++++++++++++++++------------------------ res/values-sl/strings.xml | 41 +++++++++++++++++------------------------ res/values-sr/strings.xml | 41 +++++++++++++++++------------------------ res/values-sv/strings.xml | 41 +++++++++++++++++------------------------ res/values-sw/strings.xml | 24 ++++++++++++++++-------- res/values-th/strings.xml | 41 +++++++++++++++++------------------------ res/values-tl/strings.xml | 41 +++++++++++++++++------------------------ res/values-tr/strings.xml | 41 +++++++++++++++++------------------------ res/values-uk/strings.xml | 18 +++++++++++++----- res/values-vi/strings.xml | 41 +++++++++++++++++------------------------ res/values-zh-rCN/strings.xml | 20 ++++++++++++++------ res/values-zh-rTW/strings.xml | 18 +++++++++++++----- res/values-zu/strings.xml | 20 ++++++++++++++------ 48 files changed, 713 insertions(+), 629 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 8b5638e..d97041b 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -9,18 +9,26 @@ "Raak om aan hierdie persoon jou kontakinligting te gee." "NFC geaktiveer." "Raak en straal" - "Straling aan die gang" + "Inkomende straal..." "Straling voltooi" - "Straling het misluk" + + + + + + "Raak om te bekyk" "Koppel tans" "Gekoppel" - "Kon nie verbind nie" + + "Ontkoppel tans" "Ontkoppel" "Saambinding" - "Kon nie saambind nie" - "Kon nie Bluetooth aktiveer nie" + + + + "Is jy seker jy wil die Bluetooth-toestel, %1$s, saambind?" "Ja" "Nee" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 14d1e1d..bf4e383 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -9,18 +9,26 @@ "ለዚህ ሰው የአንተን ዕውቅያ መረጃ ለመስጠት መታ አድርግ" "NFC ነቅቷል፡፡" "ለማብራት ንካ" - "ሞገድ በሂደት ላይ" - "ሞገድ ተጠናቅቋል" - "ሞገድ አልተሳካም" + "ገቢ ሞገድ..." + "አመልማሎ ተጠናቅቋል" + + + + + + "ለማየት ንካ" "በመገናኘት ላይ" "ተገናኝቷል" - "መገናኘት አልተሳካም" + + "ግንኙነት በማቋረጥ ላይ" "ግንኙነት ተቋርጧል" "በማጣመር ላይ" - "ማጣመር አልተሳካም" - "ብሉቱዝ ማንቃት አልተሳካም" + + + + "እርግጠኛ ነህ የብሉቱዝ መሣሪያው %1$sን ማጣመር ትፈልጋለህ?" "አዎ" "የለም" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 4e1a92d..1a55a35 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -9,34 +9,27 @@ "المس لمنح هذا الشخص معلومات اتصالك." "تم تمكين NFC." "المس لرسم شعاع" - + "شعاع وارد..." + "اكتمل الشعاع" + - + - + - + "المس ليتم العرض" + "جارٍ الاتصال..." + "متصل" + - + "جارٍ قطع الاتصال" + "غير متصل" + "جارٍ الإقران..." + - - - - - - - - - - - - - - - - - - - + + "هل تريد بالتأكيد إقران جهاز بلوتوث %1$s؟" + "نعم" + "لا" diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 9c68149..cc5c828 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -9,18 +9,26 @@ "Націсніце, каб даслаць гэтаму чалавеку сваю кантактн. інфармацыю" "NFC ўключаны." "Краніце, каб перадаць" - "Ідзе працэс перадачы Beam" + "Уваходная перадача beam..." "Працэс перадачы Beam завершаны" - "Няўдалы працэс перадачы Beam" + + + + + + "Націсніце, каб прагледзець" "Падключэнне" "Падключана" - "Не атрымалася падключыцца" + + "Адключэнне" "Адключана" "Падлучэнне" - "Не атрымалася выканаць падлучэнне" - "Не атрымалася ўключыць Bluetooth" + + + + "Вы ўпэўнены, што жадаеце падлучыць прыладу Bluetooth %1$s?" "Так" "Не" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 0d8f13c..075c7f9 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -9,18 +9,26 @@ "Докоснете, за да дадете на този човек информацията си за връзка." "КБП е активирана." "Докоснете, за да излъчите" - "Излъчването е в ход" + "Входящо излъчване..." "Излъчването завърши" - "Излъчването не бе успешно" + + + + + + "Докоснете, за да видите" "Свързва се" "Има връзка" - "Свързването не бе успешно" + + "Изключва се" "Изключено" "Извършва се сдвояване" - "Сдвояването не бе успешно" - "Активирането на Bluetooth не бе успешно" + + + + "Наистина ли искате да сдвоите устройството с Bluetooth %1$s?" "Да" "Не" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 2f8513d..0075630 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -9,34 +9,27 @@ "Toca per donar la teva informació de contacte a aquesta persona." "NFC activat." "Toca per fer brillar" - + "Transferència d\'entrada..." + "Sensor completat" + - + - + - + "Toca per visualitzar" + "S\'està connectant" + "Connectat" + - + "S\'està desconnectant" + "Desconnectat" + "Sincronització" + - - - - - - - - - - - - - - - - - - - + + "Estàs segur que vols sincronitzar el dispositiu Bluetooth %1$s?" + "Sí" + "No" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 17f43d5..fdf8256 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -9,18 +9,26 @@ "Klepnutím této osobě předáte své kontaktní informace." "Funkce NFC povolena." "Přenos zahájíte dotykem" - "Probíhá přenos" + "Příchozí přenos..." "Přenos dokončen" - "Přenos se nezdařil" + + + + + + "Zobrazte dotykem" "Připojování" "Připojeno" - "Připojení se nezdařilo" + + "Odpojování" "Odpojeno" "Párování" - "Párování se nezdařilo" - "Aktivace Bluetooth se nezdařila" + + + + "Opravdu chcete spárovat zařízení Bluetooth %1$s?" "Ano" "Ne" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index a032d09..844aa89 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -9,18 +9,26 @@ "Tryk for at give denne person dine kontaktoplysninger." "NFC er aktiveret." "Tryk for at overføre" - "Overførsel i gang" + "Indgående overførsel..." "Overførsel fuldført" - "Overførslen mislykkedes" - "Tryk for at få vist" + + + + + + + "Tryk for at se" "Opretter forbindelse" "Forbundet" - "Der kunne ikke oprettes forbindelse" + + "Afbryder forbindelse" "Afbrudt" "Parrer" - "Kunne ikke parres" - "Bluetooth kunne ikke aktiveres" + + + + "Er du sikker på du vil parre Bluetooth-enheden %1$s?" "Ja" "Nej" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 629620f..84d07d4 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -9,18 +9,26 @@ "Zum Weitergeben Ihrer Kontaktinformationen an diese Person tippen" "NFC aktiviert" "Zum Beamen berühren" - "Beamen läuft" + "Beam wird empfangen..." "Beamen abgeschlossen" - "Fehler beim Beamen" - "Zum Ansehen berühren" + + + + + + + "Zum Anzeigen berühren" "Verbindung wird hergestellt" "Verbunden" - "Verbindung konnte nicht aufgebaut werden." + + "Verbindung wird aufgehoben" "Verbindung getrennt" "Pairing erfolgt" - "Fehler beim Pairing" - "Bluetooth konnte nicht aktiviert werden." + + + + "Möchten Sie das Bluetooth-Gerät %1$s wirklich koppeln?" "Ja" "Nein" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 7e8ab8a..5e0a5a1 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -9,18 +9,26 @@ "Αγγίξτε για να δώσετε σε αυτό το άτομο τα στοιχεία επικοινωνίας σας." "Ενεργοποίηση ΕΚΠ." "Αγγίξτε για μετάδοση" - "Η ζεύξη βρίσκεται σε εξέλιξη" + "Εισερχόμενη ζεύξη..." "Ολοκλήρωση ζεύξης" - "Αποτυχία ζεύξης" + + + + + + "Αγγίξτε για προβολή" "Σύνδεση" "Συνδέθηκε" - "Αποτυχία σύνδεσης" + + "Αποσύνδεση" "Σε αποσύνδεση" "Σύζευξη" - "Αποτυχία σύζευξης" - "Αποτυχία ενεργοποίησης του Bluetooth" + + + + "Είστε βέβαιοι ότι θέλετε να γίνει σύζευξη της συσκευής Bluetooth %1$s;" "Ναι" "Όχι" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index eb665aa..24cffdd 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -9,18 +9,26 @@ "Touch to give this person your contact info." "NFC enabled." "Touch to beam" - "Beam in progress" + "Incoming beam..." "Beam complete" - "Beam failed" + + + + + + "Touch to view" "Connecting..." "Connected" - "Failed to connect" + + "Disconnecting" "Disconnected" "Pairing" - "Failed to pair" - "Failed to enable Bluetooth" + + + + "Are you sure you want to pair the Bluetooth device %1$s?" "Yes" "No" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 9cb7ac1..a78b18f 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -9,18 +9,26 @@ "Toca para que esta persona obtenga tu información de contacto." "Se habilitó la NFC." "Tocar para transmitir" - "Transmisión en curso" + "Transmisión entrante..." "Transmisión completa" - "Se produjo un error al transmitir el contenido." + + + + + + "Toca para ver" "Conectando..." "Conectados" - "Se produjo un error al establecer conexión." + + "Desconectando..." "Desconectados" - "Sincronización" - "Se produjo un error al establecer la sincronización." - "Se produjo un error al activar Bluetooth." + "Sincronizando..." + + + + "¿Realmente deseas sincronizar el dispositivo Bluetooth %1$s?" "Sí" "No" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index c5f5b4c..0df54ab 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -9,18 +9,26 @@ "Toca para compartir tu información de contacto con esta persona." "NFC habilitada" "Toca para compartir" - "Transferencia en curso" + "Transferencia entrante..." "Transferencia completada" - "Error al transferir contenido" + + + + + + "Tocar para ver" "Conectando..." "Conectado" - "Error de conexión" + + "Desconectando..." "Desconectado" "Sincronizando..." - "Error de sincronización" - "Error al habilitar Bluetooth" + + + + "¿Seguro que quieres sincronizar el dispositivo Bluetooth %1$s?" "Sí" "No" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 4dabd05..dfee034 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -9,18 +9,26 @@ "Puudutage, et anda sellele inimesele oma kontaktandmed." "NFC lubatud." "Puudutage kiire kasutamiseks" - "Kiir on pooleli" + "Sissetulev kiir ..." "Kiir on valmis" - "Kiir ebaõnnestus" + + + + + + "Puudutage vaatamiseks" "Ühendamine" "Ühendatud" - "Ühendamine ebaõnnestus" + + "Ühenduse katkestamine" "Ühendus on katkestatud" "Ühildamine" - "Ühildamine ebaõnnestus" - "Bluetoothi lubamine ebaõnnestus" + + + + "Kas soovite kindlasti ühildada Bluetoothi seadme %1$s?" "Jah" "Ei" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 04539b1..9a20523 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -9,34 +9,27 @@ "لمس کنید تا اطلاعات تماس خود را به این فرد بدهید." "با NFC فعال شده." "برای پخش، لمس کنید" - + "درحال دریافت پرتو..." + "پرتو ارسال شد" + - + - + - + "برای مشاهده لمس کنید" + "در حال اتصال" + "اتصال برقرار شد" + - + "در حال قطع اتصال" + "اتصال قطع شد" + "در حال مرتبط سازی" + - - - - - - - - - - - - - - - - - - - + + "آیا مطمئن هستید که می‌خواهید دستگاه بلوتوث %1$s را مرتبط کنید؟" + "بله" + "خیر" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index b6abbf8..741e7a9 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -9,18 +9,26 @@ "Anna tälle henkilölle yhteystietosi koskettamalla." "NFC otettu käyttöön." "Kosketa palkkia" - "Sisällön jako käynnissä" + "Saapuva sisällönjakopyyntö..." "Sisältö jaettu" - "Sisällön jako epäonnistui" + + + + + + "Kosketa ja näytä" "Yhdistetään" "Yhdistetty" - "Yhteyden muodostaminen epäonnistui" + + "Katkaistaan yhteyttä" "Yhteys katkaistu" "Laiteparia muodostetaan" - "Laiteparin muodostus epäonnistui" - "Bluetoothin käyttöön ottaminen epäonnistui" + + + + "Oletko varma, että haluat muodostaa laiteparin Bluetooth-laitteeseen %1$s?" "Kyllä" "Ei" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 569fc68..27cac47 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -9,18 +9,26 @@ "Appuyez pour communiquer vos coordonnées à cette personne." "NFC activée" "Appuyer pour partager" - "Partage en cours…" + "Partage entrant..." "Partage terminé." - "Échec du partage." + + + + + + "Appuyer pour afficher" "Connexion en cours…" "Connecté" - "Échec de la connexion." + + "Déconnexion en cours…" "Déconnecté" "Association en cours…" - "Échec de l\'association." - "Échec de l\'activation du Bluetooth." + + + + "Voulez-vous vraiment associer l\'appareil Bluetooth %1$s ?" "Oui" "Non" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index dd74683..96a837f 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -9,18 +9,26 @@ "इस व्‍यक्ति को अपनी संपर्क जानकारी देने के लिए स्‍पर्श करें." "NFC सक्षम है." "बीम करने के लिए स्पर्श करें" - "बीम चल रहा है" + "इनकमिंग बीम..." "बीम करना पूर्ण" - "बीम करना विफल रहा" + + + + + + "देखने के लिए स्‍पर्श करें" "कनेक्ट हो रहा है" "कनेक्ट है" - "जोड़ने में विफल रहा" + + "डिस्कनेक्ट कर रहा है" "डिस्कनेक्ट किया गया" "युग्मन" - "युग्मित करने में विफल रहा" - "Bluetooth सक्षम करने में विफल रहा" + + + + "क्‍या आप वाकई Bluetooth उपकरण %1$s को युग्मित करना चाहते हैं?" "हां" "नहीं" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 57b12c5..15bc79e 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -9,18 +9,26 @@ "Dodirnite kako biste ovoj osobi dali svoje podatke za kontakt." "NFC omogućen." "Dodirnite za emitiranje" - "Emitiranje u tijeku" + "Dolazno emitiranje..." "Emitiranje je završeno" - "Emitiranje nije uspjelo" + + + + + + "Dodirnite za prikaz" "Povezivanje" "Povezan" - "Povezivanje nije uspjelo" + + "Prekid veze" "Prekinuta veza" "Uparivanje" - "Uparivanje nije uspjelo" - "Omogućavanje Bluetootha nije uspjelo" + + + + "Jeste li sigurni da želite upariti Bluetooth uređaj %1$s?" "Da" "Ne" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index e306bb8..69e00f0 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -9,18 +9,26 @@ "Érintse meg kapcsolatfelvételi adatok megosztásához." "NFC bekapcsolva" "Érintse meg a sugárzáshoz" - "Átvitel folyamatban." + "Bejövő sugár..." "Átvitel befejezve." - "Átvitel sikertelen." + + + + + + "A megtekintéshez érintse meg." "Csatlakozás" "Csatlakozva" - "Sikertelen csatlakozás." + + "Szétkapcsolás" "Szétkapcsolva" "Párosítás" - "Nem sikerült párosítani." - "Nem sikerült bekapcsolni a Bluetootht." + + + + "Biztosan párosítani szeretné a(z) %1$s Bluetooth-eszközt?" "Igen" "Nem" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index a82e1c1..6cd0a24 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -9,18 +9,26 @@ "Sentuh untuk memberikan orang ini info kontak Anda." "NFC diaktifkan." "Sentuh untuk menyorot" - "Beam sedang berlangsung" + "Pancaran yang masuk..." "Beam selesai" - "Beam gagal" + + + + + + "Sentuh untuk melihat" "Menyambungkan" "Tersambung" - "Gagal menyambungkan" + + "Memutuskan" "Terputus" "Menyandingkan" - "Gagal menyandingkan" - "Gagal mengaktifkan Bluetooth" + + + + "Yakin ingin menyandingkan perangkat Bluetooth %1$s?" "Ya" "Tidak" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index eb3c77f..1af8111 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -9,18 +9,26 @@ "Tocca per inviare a questa persona le informazioni di contatto" "Comunicazione NFC abilitata." "Tocca per trasmettere" - "Trasmissione in corso" + "Trasmissione in arrivo..." "Trasmissione completata" - "Trasmissione non riuscita" + + + + + + "Tocca per visualizzare" "Collegamento in corso" "Collegato" - "Errore di connessione" + + "Scollegamento in corso" "Scollegato" "Accoppiamento" - "Impossibile accoppiare" - "Impossibile attivare il Bluetooth" + + + + "Vuoi accoppiare il dispositivo Bluetooth %1$s?" "Sì" "No" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 0f50aa3..b5a28ea 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -9,18 +9,26 @@ "גע כדי לתת למשתמש זה את פרטי הקשר שלך" "NFC מופעל." "גע כדי להקרין" - "הקרנה מתבצעת" + "קרן נכנסת..." "הקרנה הושלמה" - "הקרנה נכשלה" + + + + + + "גע כדי להציג" "מתחבר" "מחובר" - "ההתחברות נכשלה" + + "מתנתק" "מנותק" "התאמה" - "ההתאמה נכשלה" - "הפעלת Bluetooth נכשלה" + + + + "האם אתה בטוח שאתה רוצה להתאים את מכשיר ה-Bluetooth %1$s?" "כן" "לא" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 0b1466a..e22d1a9 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -9,34 +9,27 @@ "このユーザーに連絡先情報を提供するにはタッチします。" "NFCは有効です。" "タップしてビーム" - + "ビームを受信しています..." + "ビーム完了" + - + - + - + "タップして表示" + "接続中" + "接続されました" + - + "切断中" + "切断されました" + "ペア設定" + - - - - - - - - - - - - - - - - - - - + + "Bluetoothデバイス%1$sをペアに設定してもよろしいですか?" + "はい" + "いいえ" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 9cb341f..af53f56 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -9,34 +9,27 @@ "이 사람에게 내 연락처 정보를 제공하려면 터치하세요." "NFC 사용" "공유하기" - + "수신 빔..." + "Beam 완료" + - + - + - + "터치하여 보기" + "연결 중" + "연결됨" + - + "연결을 끊는 중" + "연결 끊김" + "페어링 중" + - - - - - - - - - - - - - - - - - - - + + "블루투스 기기 %1$s을(를) 페어링하시겠습니까?" + "예" + "아니요" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index df9294f..128dc76 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -9,34 +9,27 @@ "Palieskite, kad šiam asmeniui suteiktumėte savo kontakt. inf." "ALR įgalinta." "Jei norite perduoti, palieskite" - + "Gaunamas perdavimas..." + "Perdavimas baigtas" + - + - + - + "Jei norite peržiūrėti, palieskite" + "Prisijungiama" + "Prisijungta" + - + "Atsijungiama" + "Atsijungta" + "Susiejama" + - - - - - - - - - - - - - - - - - - - + + "Ar tikrai norite susieti „Bluetooth“ įrenginį „%1$s“?" + "Taip" + "Ne" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 84334e9..3653f42 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -9,34 +9,27 @@ "Pieskarieties, lai sniegtu šai personai savu kontaktinformāciju." "NFC ir iespējoti." "Pieskarties, lai projicētu" - + "Ienākošie vienumi, izmantojot funkciju Beam..." + "Kopīgošana, izmantojot funkciju Beam, ir pabeigta." + - + - + - + "Pieskarieties, lai skatītu." + "Notiek savienojuma izveide" + "Savienojums izveidots" + - + "Notiek savienojuma pārtraukšana" + "Savienojums pārtraukts" + "Notiek savienošana pārī" + - - - - - - - - - - - - - - - - - - - + + "Vai tiešām vēlaties savienot pārī Bluetooth ierīci %1$s?" + "Jā" + "Nē" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index bdeb342..cddf43e 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -9,18 +9,26 @@ "Sentuh untuk memberi orang ini maklumat hubungan anda." "NFC didayakan." "Sentuh untuk memancarkan" - "Pancar sedang berjalan" + "Pancar sedang masuk..." "Pancar selesai" - "Pancar gagal" + + + + + + "Sentuh untuk melihat" "Menyambung" "Disambungkan" - "Gagal menyambung" + + "Memutuskan sambungan" "Diputuskan sambungan" "Menjadikan pasangan" - "Gagal untuk berpasangan" - "Gagal untuk mendayakan Bluetooth" + + + + "Adakah anda pasti anda mahu memadankan peranti Bluetooth %1$s?" "Ya" "Tidak" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index ec9ae5a..5e0d039 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -9,34 +9,27 @@ "Berør for å gi denne personen kontaktinformasjonen din." "NFC er aktivert." "Berør for å overføre trådløst" - + "Innkommende trådløs overføring" + "Overføring fullført" + - + - + - + "Trykk for å se" + "Kobler til" + "Tilkoblet" + - + "Frakobler" + "Frakoblet" + "Kobler til" + - - - - - - - - - - - - - - - - - - - + + "Er du sikker på at koble til Bluetooth-enheten %1$s?" + "Ja" + "Nei" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index c5d57f0..874d389 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -9,34 +9,27 @@ "Raak aan om deze persoon uw contactgegevens te geven." "NFC ingeschakeld." "Tikken om uit te zenden" - + "Inkomende beam..." + "Beam voltooid" + - + - + - + "Raak aan om te bekijken" + "Verbinding maken" + "Verbonden" + - + "Loskoppelen" + "Losgekoppeld" + "Koppelen" + - - - - - - - - - - - - - - - - - - - + + "Weet u zeker dat u het Bluetooth-apparaat %1$s wilt koppelen?" + "Ja" + "Nee" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 55f56b2..822dba6 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -9,34 +9,27 @@ "Dotknij, aby przekazać tej osobie swoje dane kontaktowe." "Komunikacja NFC włączona." "Dotknij, aby przesłać" - + "Odbieram dane zbliżeniowo..." + "Przesyłanie zbliżeniowe zakończone" + - + - + - + "Dotknij, by wyświetlić" + "Łączenie" + "Połączono" + - + "Rozłączanie" + "Rozłączone" + "Tworzenie sparowania" + - - - - - - - - - - - - - - - - - - - + + "Czy na pewno chcesz sparować urządzenie Bluetooth %1$s?" + "Tak" + "Nie" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index d00c09e..8b834d9 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -9,34 +9,27 @@ "Toque para dar a esta pessoa as suas informações de contacto." "NFC ativado." "Toque para transmitir" - + "A receber partilha..." + "Partilha concluída" + - + - + - + "Tocar para ver" + "A ligar" + "Ligado" + - + "A desligar" + "Desligado" + "A sincronizar" + - - - - - - - - - - - - - - - - - - - + + "Tem a certeza de que pretende sincronizar o dispositivo Bluetooth %1$s?" + "Sim" + "Não" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 54c214d..13c824e 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -9,18 +9,26 @@ "Toque para fornecer suas informações de contato para essa pessoa" "NFC habilitado." "Toque para iluminar" - "Irradiação em andamento" + "Feixe de entrada..." "Irradiação concluída" - "Falha na irradiação" + + + + + + "Toque para visualizar" "Conectando" "Conectado" - "Falha ao conectar" + + "Desconectando" "Desconectado" "Pareando" - "Falha no pareamento" - "Falha ao ativar o Bluetooth" + + + + "Tem certeza de que deseja parear o dispositivo Bluetooth %1$s?" "Sim" "Não" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 7888de7..b753f6c 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -9,34 +9,27 @@ "Atingeţi pentru a oferi acestei persoane datele dvs. de contact" "NFC activat." "Atingeţi pentru transmitere" - + "Transmitere primită..." + "Transmitere încheiată" + - + - + - + "Atingeţi pentru a afişa" + "Se conectează" + "Conectat" + - + "Se deconectează" + "Deconectat" + "Se împerechează" + - - - - - - - - - - - - - - - - - - - + + "Sigur doriţi să împerecheaţi dispozitivul Bluetooth %1$s?" + "Da" + "Nu" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index a142798..08c983f 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -9,18 +9,26 @@ "Нажмите, чтобы передать свои контактные данные." "Служба NFC включена" "Нажмите, чтобы передать данные" - "Передача данных…" + "Получение данных…" "Передача данных завершена" - "Не удалось передать данные" + + + + + + "Нажмите, чтобы просмотреть" "Подключение…" "Подключено" - "Сбой соединения" + + "Отключение…" "Отключено" "Подключение…" - "Ошибка подключения" - "Не удалось включить Bluetooth" + + + + "Подключить Bluetooth-устройство %1$s?" "Да" "Нет" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index b149c6d..a10de01 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -9,34 +9,27 @@ "Dotknutím sa tejto osobe odovzdáte svoje kontaktné informácie." "NFC povolené." "Dotykom spustíte prenos" - + "Prichádzajúci prenos..." + "Prenos bol dokončený" + - + - + - + "Zobrazte dotykom" + "Prebieha pripájanie" + "Pripojené" + - + "Prebieha odpájanie" + "Odpojené" + "Prebieha párovanie" + - - - - - - - - - - - - - - - - - - - + + "Naozaj chcete spárovať zariadenie Bluetooth %1$s?" + "Áno" + "Nie" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index ef8e47d..0211442 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -9,34 +9,27 @@ "Tapnite, če želite tej osebi poslati svoje podatke za stik." "NFC omogočen." "Dotaknite se, da pošljete" - + "Dohodni prenos ..." + "Prenos končan" + - + - + - + "Dotaknite se za prikaz" + "Vzpostavljanje povezave" + "Povezano" + - + "Prekinjanje povezave" + "Ni povezave" + "Seznanjanje" + - - - - - - - - - - - - - - - - - - - + + "Ste prepričani, da želite seznaniti napravo Bluetooth %1$s?" + "Da" + "Ne" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 7f28427..211698d 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -9,34 +9,27 @@ "Додирните да бисте овој особи дали контакт информације." "NFC је омогућен." "Додирните за емитовање" - + "Долазно пребацивање..." + "Пребацивање је довршено" + - + - + - + "Додирните да бисте прегледали" + "Повезивање" + "Повезано" + - + "Прекидање везе" + "Веза је прекинута" + "Упаривање" + - - - - - - - - - - - - - - - - - - - + + "Да ли сте сигурни да желите да упарите Bluetooth уређај %1$s?" + "Да" + "Не" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 52e61ce..33b1c46 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -9,34 +9,27 @@ "Tryck om du vill ge personen dina kontaktuppgifter." "NFC aktiverat." "Tryck här om du vill överföra" - + "Inkommande trådlös överföring ..." + "Den trådlösa överföringen har slutförts" + - + - + - + "Tryck och visa" + "Anslutningen upprättas" + "Anslutningen har upprättats" + - + "Anslutningen avbryts" + "Frånkopplad" + "Parkoppling upprättas" + - - - - - - - - - - - - - - - - - - - + + "Är du säker på att du vill para ihop Bluetooth-enheten %1$s?" + "Ja" + "Nej" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 07a72c5..23f0a95 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -9,19 +9,27 @@ "Gusa ili kumpa mtu huyu maelezo yako ya mawasiliano." "NFC imewezeshwa." "Gusa kwa boriti" - "Boriti inaendelea" + "Boriti zinazoingia..." "Boriti umekamilika" - "Boriti alishindwa" + + + + + + "Gusa ili utazame" "Inaunganisha" "Imeunganishwa" - "Haikuweza kuunganisha." - "Inakata muunganisho..." + + + "Inakata muunganisho" "Imekata muunganisho" - "Inalinganisha" - "Imeshindwa kulinganisha" - "Imeshindwa kuwawezesha Bluetooth" - "Una uhakika unataka kuunganisha kifaa chako chathe Bluetooth cha %1$s?" + "Kuoanisha" + + + + + "Una uhakika unataka kuoanisha kifaa cha Bluetooth cha %1$s?" "Ndiyo" "Hapana" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index e0e2113..4e5ed93 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -9,34 +9,27 @@ "แตะเพื่อให้ข้อมูลที่อยู่ติดต่อของคุณแก่คนนี้" "เปิดใช้งาน NFC แล้ว" "แตะเพื่อส่ง" - + "บีมขาเข้า..." + "บีมสำเร็จ" + - + - + - + "แตะเพื่อดู" + "กำลังเชื่อมต่อ" + "เชื่อมต่อแล้ว" + - + "กำลังเลิกเชื่อมต่อ" + "เลิกเชื่อมต่อแล้ว" + "กำลังจับคู่อุปกรณ์" + - - - - - - - - - - - - - - - - - - - + + "คุณแน่ใจหรือไม่ว่าต้องการจับคู่อุปกรณ์บลูทูธ %1$s นี้" + "ใช่" + "ไม่" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 9f0bdcf..5aeeee5 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -9,34 +9,27 @@ "Pindutin para ibigay sa taong ito ang impormasyon ng contact mo" "Pinagana ang NFC." "Pindutin upang i-beam" - + "Dumarating na beam..." + "Kumpleto na ang pag-beam" + - + - + - + "Pindutin upang tingnan" + "Kumokonekta" + "Nakakonekta" + - + "Nagdidiskonekta" + "Nadiskonekta" + "Pinapares" + - - - - - - - - - - - - - - - - - - - + + "Sigurado ka bang nais mong ipares ang Bluetooth device na %1$s?" + "Oo" + "Hindi" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 683af8e..da96341 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -9,34 +9,27 @@ "Bu kullanıcıya kişi bilgilerinizi vermek için dokunun." "NFC etkin." "Göndermek için dokunun" - + "Gelen ışın..." + "Işınlama tamamlandı" + - + - + - + "Görüntülemek için dokunun" + "Bağlanıyor" + "Bağlandı" + - + "Bağlantı kesiliyor" + "Bağlantı kesildi" + "Eşleştiriliyor" + - - - - - - - - - - - - - - - - - - - + + "%1$s adlı Bluetooth cihazını eşleştirmek istediğinizden emin misiniz?" + "Evet" + "Hayır" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index b7b9a25..aa82f0a 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -9,18 +9,26 @@ "Торкніться, щоб надати цій особі свою контактну інформацію." "NFC увімкнено." "Торкніться, щоб передати дані" - "Виконується передавання даних" + "Вхідне передавання даних..." "Передавання даних виконано" - "Передавання даних не виконано" + + + + + + "Торкніться, щоб переглянути" "Під’єднання" "Під’єднано" - "Не вдалося під’єднатися" + + "Від’єднання" "Від’єднано" "Створення пари" - "Не вдалося створити пару" - "Не вдалося ввімкнути Bluetooth" + + + + "Дійсно створити пару з пристроєм Bluetooth %1$s?" "Так" "Ні" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 51d1818..4745a82 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -9,34 +9,27 @@ "Chạm để gửi cho người này thông tin liên hệ của bạn." "Đã bật NFC." "Chạm để truyền" - + "Tia đến..." + "Hoàn tất chiếu" + - + - + - + "Chạm để xem" + "Đang kết nối" + "Đã kết nối" + - + "Đang ngắt kết nối" + "Đã ngắt kết nối" + "Đang ghép nối" + - - - - - - - - - - - - - - - - - - - + + "Bạn có chắc chắn muốn ghép nối thiết bị Bluetooth %1$s không?" + "Có" + "Không" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index cbdba1e..7cdd6ba 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -9,18 +9,26 @@ "接触可向此人发送您的联系人信息。" "NFC 已启用。" "触摸即可发送" - "正在发送" - "发送完毕" - "发送失败" + "正在接受 Beam 发送..." + "Beam 发送完毕" + + + + + + "触摸即可查看" "正在连接" "已连接" - "无法连接" + + "正在断开连接" "已断开连接" "正在配对" - "无法配对" - "无法启用蓝牙" + + + + "您确定要与蓝牙设备%1$s配对吗?" "是" "否" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index afcbdfa..1313b82 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -9,18 +9,26 @@ "輕觸即可將您的聯絡人資訊傳送給這位使用者。" "NFC 已啟用。" "輕觸即可傳輸" - "傳輸中" + "正在接收傳輸..." "傳輸完成" - "傳輸失敗" + + + + + + "輕觸即可查看" "連線中" "已連線" - "無法連線" + + "正在中斷連線" "已中斷連線" "配對中" - "無法配對" - "無法啟用藍牙功能" + + + + "您確定要與藍牙裝置「%1$s」配對嗎?" "是" "否" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index b841678..9a21bb9 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -9,18 +9,26 @@ "Thinta ukuze unike lomuntu imininingwane yakho yokuxhumana" "I-NFC ivunyelwe." "Cindezela kwibhimu" - "I-Beam iyaqhubeka" - "I-Beam iqedile" - "I-Beam yehlulekile" + "Ukuvumelanisa okungenayo..." + "Ukuvumelanisa kuqedile" + + + + + + "Thinta ukuze ubuke" "Iyaxhuma" "Ixhunyiwe" - "Yehlulekile ukuxhuma" + + "Iyanqamula" "Inqamukile" "Iyabhangqa" - "Yehlulekile ukubhanqa" - "Yehlulekile ukunika amandla i-Bluetooth" + + + + "Ingabe unesiqinisekiso sokuthi ufuna ukuhambisa ngakubili idivayisi %1$s ye-Bluetooth?" "Yebo" "Cha" -- cgit v1.1 From ab0bde9633e75a7b04e15a9647022e46edb22ea7 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Tue, 29 May 2012 11:28:26 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I45b218ab020a6452a2954db326d014a303beb704 --- res/values-af/strings.xml | 2 ++ res/values-am/strings.xml | 20 ++++++++------------ res/values-ar/strings.xml | 2 ++ res/values-be/strings.xml | 2 ++ res/values-bg/strings.xml | 2 ++ res/values-ca/strings.xml | 20 ++++++++------------ res/values-cs/strings.xml | 2 ++ res/values-da/strings.xml | 2 ++ res/values-de/strings.xml | 2 ++ res/values-el/strings.xml | 22 +++++++++------------- res/values-en-rGB/strings.xml | 20 ++++++++------------ res/values-es-rUS/strings.xml | 2 ++ res/values-es/strings.xml | 20 ++++++++------------ res/values-et/strings.xml | 2 ++ res/values-fa/strings.xml | 2 ++ res/values-fi/strings.xml | 2 ++ res/values-fr/strings.xml | 2 ++ res/values-hi/strings.xml | 2 ++ res/values-hr/strings.xml | 2 ++ res/values-hu/strings.xml | 2 ++ res/values-in/strings.xml | 2 ++ res/values-it/strings.xml | 2 ++ res/values-iw/strings.xml | 20 ++++++++------------ res/values-ja/strings.xml | 2 ++ res/values-ko/strings.xml | 2 ++ res/values-lt/strings.xml | 2 ++ res/values-lv/strings.xml | 2 ++ res/values-ms/strings.xml | 2 ++ res/values-nb/strings.xml | 2 ++ res/values-nl/strings.xml | 2 ++ res/values-pl/strings.xml | 2 ++ res/values-pt-rPT/strings.xml | 2 ++ res/values-pt/strings.xml | 2 ++ res/values-ro/strings.xml | 2 ++ res/values-ru/strings.xml | 2 ++ res/values-sk/strings.xml | 2 ++ res/values-sl/strings.xml | 2 ++ res/values-sr/strings.xml | 2 ++ res/values-sv/strings.xml | 2 ++ res/values-sw/strings.xml | 20 ++++++++------------ res/values-th/strings.xml | 20 ++++++++------------ res/values-tl/strings.xml | 2 ++ res/values-tr/strings.xml | 2 ++ res/values-uk/strings.xml | 2 ++ res/values-vi/strings.xml | 2 ++ res/values-zh-rCN/strings.xml | 2 ++ res/values-zh-rTW/strings.xml | 2 ++ res/values-zu/strings.xml | 2 ++ 48 files changed, 145 insertions(+), 97 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index d97041b..2c32c90 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -18,6 +18,8 @@ "Raak om te bekyk" + + "Koppel tans" "Gekoppel" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index bf4e383..aa920d9 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -11,24 +11,20 @@ "ለማብራት ንካ" "ገቢ ሞገድ..." "አመልማሎ ተጠናቅቋል" - - - - - - + "ሞገድ አልተጠናቀቀም" + "ሞገድ ተሰርዧል" + "ሰርዝ" "ለማየት ንካ" + + "በመገናኘት ላይ" "ተገናኝቷል" - - + "ማገናኘት አልተቻለም" "ግንኙነት በማቋረጥ ላይ" "ግንኙነት ተቋርጧል" "በማጣመር ላይ" - - - - + "ማጣመር አልተቻለም" + "ብሉቱዝ ማንቃት አልተቻለም" "እርግጠኛ ነህ የብሉቱዝ መሣሪያው %1$sን ማጣመር ትፈልጋለህ?" "አዎ" "የለም" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 1a55a35..f038675 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -18,6 +18,8 @@ "المس ليتم العرض" + + "جارٍ الاتصال..." "متصل" diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index cc5c828..c3b355f 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -18,6 +18,8 @@ "Націсніце, каб прагледзець" + + "Падключэнне" "Падключана" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 075c7f9..3984657 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -18,6 +18,8 @@ "Докоснете, за да видите" + + "Свързва се" "Има връзка" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 0075630..aa0befa 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -11,24 +11,20 @@ "Toca per fer brillar" "Transferència d\'entrada..." "Sensor completat" - - - - - - + "El sensor no s\'ha executat" + "S\'ha desactivat el sensor" + "Cancel·la" "Toca per visualitzar" + + "S\'està connectant" "Connectat" - - + "No es pot establir connexió" "S\'està desconnectant" "Desconnectat" "Sincronització" - - - - + "No es pot sincronitzar" + "No es pot activar el Bluetooth" "Estàs segur que vols sincronitzar el dispositiu Bluetooth %1$s?" "Sí" "No" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index fdf8256..12d1bfd 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -18,6 +18,8 @@ "Zobrazte dotykem" + + "Připojování" "Připojeno" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 844aa89..b284b5b 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -18,6 +18,8 @@ "Tryk for at se" + + "Opretter forbindelse" "Forbundet" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 84d07d4..5c3c821 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -18,6 +18,8 @@ "Zum Anzeigen berühren" + + "Verbindung wird hergestellt" "Verbunden" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 5e0a5a1..cad1d4b 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -9,26 +9,22 @@ "Αγγίξτε για να δώσετε σε αυτό το άτομο τα στοιχεία επικοινωνίας σας." "Ενεργοποίηση ΕΚΠ." "Αγγίξτε για μετάδοση" - "Εισερχόμενη ζεύξη..." + "Εισερχόμενη ζεύξη…" "Ολοκλήρωση ζεύξης" - - - - - - + "Η ζεύξη δεν ολοκληρώθηκε" + "Ακύρωση ζεύξης" + "Άκυρο" "Αγγίξτε για προβολή" + + "Σύνδεση" "Συνδέθηκε" - - + "Δεν ήταν δυνατή η σύνδεση" "Αποσύνδεση" "Σε αποσύνδεση" "Σύζευξη" - - - - + "Δεν ήταν δυνατή η σύζευξη" + "Δεν ήταν δυνατή η ενεργοποίηση του Bluetooth" "Είστε βέβαιοι ότι θέλετε να γίνει σύζευξη της συσκευής Bluetooth %1$s;" "Ναι" "Όχι" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 24cffdd..c344909 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -11,24 +11,20 @@ "Touch to beam" "Incoming beam..." "Beam complete" - - - - - - + "Beam did not complete" + "Beam cancelled" + "Cancel" "Touch to view" + + "Connecting..." "Connected" - - + "Could not connect" "Disconnecting" "Disconnected" "Pairing" - - - - + "Could not pair" + "Could not enable Bluetooth" "Are you sure you want to pair the Bluetooth device %1$s?" "Yes" "No" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index a78b18f..44f8f2f 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -18,6 +18,8 @@ "Toca para ver" + + "Conectando..." "Conectados" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 0df54ab..d78117c 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -11,24 +11,20 @@ "Toca para compartir" "Transferencia entrante..." "Transferencia completada" - - - - - - + "Transferencia no completada" + "Transferencia cancelada" + "Cancelar" "Tocar para ver" + + "Conectando..." "Conectado" - - + "Error al establecer conexión" "Desconectando..." "Desconectado" "Sincronizando..." - - - - + "Error al sincronizar" + "Error al habilitar Bluetooth" "¿Seguro que quieres sincronizar el dispositivo Bluetooth %1$s?" "Sí" "No" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index dfee034..c366629 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -18,6 +18,8 @@ "Puudutage vaatamiseks" + + "Ühendamine" "Ühendatud" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 9a20523..447ca15 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -18,6 +18,8 @@ "برای مشاهده لمس کنید" + + "در حال اتصال" "اتصال برقرار شد" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 741e7a9..d3252ba 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -18,6 +18,8 @@ "Kosketa ja näytä" + + "Yhdistetään" "Yhdistetty" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 27cac47..b7b68d8 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -18,6 +18,8 @@ "Appuyer pour afficher" + + "Connexion en cours…" "Connecté" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 96a837f..22ac17b 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -18,6 +18,8 @@ "देखने के लिए स्‍पर्श करें" + + "कनेक्ट हो रहा है" "कनेक्ट है" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 15bc79e..6ac252b 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -18,6 +18,8 @@ "Dodirnite za prikaz" + + "Povezivanje" "Povezan" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 69e00f0..2803945 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -18,6 +18,8 @@ "A megtekintéshez érintse meg." + + "Csatlakozás" "Csatlakozva" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 6cd0a24..4d19d53 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -18,6 +18,8 @@ "Sentuh untuk melihat" + + "Menyambungkan" "Tersambung" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 1af8111..48ea9d2 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -18,6 +18,8 @@ "Tocca per visualizzare" + + "Collegamento in corso" "Collegato" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index b5a28ea..a777df6 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -11,24 +11,20 @@ "גע כדי להקרין" "קרן נכנסת..." "הקרנה הושלמה" - - - - - - + "הקרן לא הושלמה" + "הקרן בוטלה" + "ביטול" "גע כדי להציג" + + "מתחבר" "מחובר" - - + "לא ניתן להתחבר." "מתנתק" "מנותק" "התאמה" - - - - + "לא ניתן לבצע התאמה" + "לא ניתן להפעיל Bluetooth" "האם אתה בטוח שאתה רוצה להתאים את מכשיר ה-Bluetooth %1$s?" "כן" "לא" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index e22d1a9..a0c15bd 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -18,6 +18,8 @@ "タップして表示" + + "接続中" "接続されました" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index af53f56..132c046 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -18,6 +18,8 @@ "터치하여 보기" + + "연결 중" "연결됨" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 128dc76..448f62e 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -18,6 +18,8 @@ "Jei norite peržiūrėti, palieskite" + + "Prisijungiama" "Prisijungta" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 3653f42..82939a2 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -18,6 +18,8 @@ "Pieskarieties, lai skatītu." + + "Notiek savienojuma izveide" "Savienojums izveidots" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index cddf43e..d5f3163 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -18,6 +18,8 @@ "Sentuh untuk melihat" + + "Menyambung" "Disambungkan" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 5e0d039..2d294db 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -18,6 +18,8 @@ "Trykk for å se" + + "Kobler til" "Tilkoblet" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 874d389..1d94a1f 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -18,6 +18,8 @@ "Raak aan om te bekijken" + + "Verbinding maken" "Verbonden" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 822dba6..3da2db8 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -18,6 +18,8 @@ "Dotknij, by wyświetlić" + + "Łączenie" "Połączono" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 8b834d9..8bb6520 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -18,6 +18,8 @@ "Tocar para ver" + + "A ligar" "Ligado" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 13c824e..7f009e5 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -18,6 +18,8 @@ "Toque para visualizar" + + "Conectando" "Conectado" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index b753f6c..ce71a2b 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -18,6 +18,8 @@ "Atingeţi pentru a afişa" + + "Se conectează" "Conectat" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 08c983f..0459a11 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -18,6 +18,8 @@ "Нажмите, чтобы просмотреть" + + "Подключение…" "Подключено" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index a10de01..a400c01 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -18,6 +18,8 @@ "Zobrazte dotykom" + + "Prebieha pripájanie" "Pripojené" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 0211442..67e4786 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -18,6 +18,8 @@ "Dotaknite se za prikaz" + + "Vzpostavljanje povezave" "Povezano" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 211698d..859f0dd 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -18,6 +18,8 @@ "Додирните да бисте прегледали" + + "Повезивање" "Повезано" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 33b1c46..15dbb2d 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -18,6 +18,8 @@ "Tryck och visa" + + "Anslutningen upprättas" "Anslutningen har upprättats" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 23f0a95..8b0f9d9 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -11,24 +11,20 @@ "Gusa kwa boriti" "Boriti zinazoingia..." "Boriti umekamilika" - - - - - - + "Boriti haikukamilisha" + "Boriti imeghairiwa" + "Ghairi" "Gusa ili utazame" + + "Inaunganisha" "Imeunganishwa" - - + "Haikuweza kuunganisha" "Inakata muunganisho" "Imekata muunganisho" "Kuoanisha" - - - - + "Haikuweza kuoanisha" + "Haikuweza kuwawezesha Bluetooth" "Una uhakika unataka kuoanisha kifaa cha Bluetooth cha %1$s?" "Ndiyo" "Hapana" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 4e5ed93..075744a 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -11,24 +11,20 @@ "แตะเพื่อส่ง" "บีมขาเข้า..." "บีมสำเร็จ" - - - - - - + "บีมไม่เสร็จสมบูรณ์" + "ยกเลิกบีมแล้ว" + "ยกเลิก" "แตะเพื่อดู" + + "กำลังเชื่อมต่อ" "เชื่อมต่อแล้ว" - - + "เชื่อมต่อไม่ได้" "กำลังเลิกเชื่อมต่อ" "เลิกเชื่อมต่อแล้ว" "กำลังจับคู่อุปกรณ์" - - - - + "ไม่สามารถจับคู่อุปกรณ์" + "ไม่สามารถเปิดใช้งานบลูทูธ" "คุณแน่ใจหรือไม่ว่าต้องการจับคู่อุปกรณ์บลูทูธ %1$s นี้" "ใช่" "ไม่" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 5aeeee5..2c65adc 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -18,6 +18,8 @@ "Pindutin upang tingnan" + + "Kumokonekta" "Nakakonekta" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index da96341..a9169cc 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -18,6 +18,8 @@ "Görüntülemek için dokunun" + + "Bağlanıyor" "Bağlandı" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index aa82f0a..0086aac 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -18,6 +18,8 @@ "Торкніться, щоб переглянути" + + "Під’єднання" "Під’єднано" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 4745a82..c40cc16 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -18,6 +18,8 @@ "Chạm để xem" + + "Đang kết nối" "Đã kết nối" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 7cdd6ba..b6fa370 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -18,6 +18,8 @@ "触摸即可查看" + + "正在连接" "已连接" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 1313b82..5e91881 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -18,6 +18,8 @@ "輕觸即可查看" + + "連線中" "已連線" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 9a21bb9..6e34222 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -18,6 +18,8 @@ "Thinta ukuze ubuke" + + "Iyaxhuma" "Ixhunyiwe" -- cgit v1.1 From 771575908dff999cf8c80df7b135298c52ce0b2e Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Wed, 30 May 2012 10:43:26 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I17048d6769349b28c3ca1f9e7bf3314a81027eb7 --- res/values-ar/strings.xml | 18 ++++++------------ res/values-en-rGB/strings.xml | 3 +-- res/values-es-rUS/strings.xml | 18 ++++++------------ res/values-et/strings.xml | 18 ++++++------------ res/values-fa/strings.xml | 18 ++++++------------ res/values-in/strings.xml | 18 ++++++------------ res/values-it/strings.xml | 3 +-- res/values-ko/strings.xml | 18 ++++++------------ res/values-lt/strings.xml | 18 ++++++------------ res/values-lv/strings.xml | 18 ++++++------------ res/values-ms/strings.xml | 18 ++++++------------ res/values-pl/strings.xml | 18 ++++++------------ res/values-pt/strings.xml | 18 ++++++------------ res/values-tl/strings.xml | 18 ++++++------------ res/values-uk/strings.xml | 18 ++++++------------ res/values-vi/strings.xml | 18 ++++++------------ res/values-zu/strings.xml | 18 ++++++------------ 17 files changed, 92 insertions(+), 184 deletions(-) diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index f038675..28ddb1d 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -11,26 +11,20 @@ "المس لرسم شعاع" "شعاع وارد..." "اكتمل الشعاع" - - - - - - + "لم يكتمل الشعاع" + "تم إلغاء الشعاع" + "إلغاء" "المس ليتم العرض" "جارٍ الاتصال..." "متصل" - - + "تعذر الاتصال" "جارٍ قطع الاتصال" "غير متصل" "جارٍ الإقران..." - - - - + "تعذر الإقران" + "تعذر تمكين بلوتوث" "هل تريد بالتأكيد إقران جهاز بلوتوث %1$s؟" "نعم" "لا" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index c344909..cc8d695 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -15,8 +15,7 @@ "Beam cancelled" "Cancel" "Touch to view" - - + "The receiver\'s device doesn\'t support large file transfer via beam." "Connecting..." "Connected" "Could not connect" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 44f8f2f..16bf63a 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -11,26 +11,20 @@ "Tocar para transmitir" "Transmisión entrante..." "Transmisión completa" - - - - - - + "La transferencia no se completó" + "Transferencia cancelada" + "Cancelar" "Toca para ver" "Conectando..." "Conectados" - - + "No se pudo conectar" "Desconectando..." "Desconectados" "Sincronizando..." - - - - + "No se pudo vincular" + "Error al habilitar Bluetooth" "¿Realmente deseas sincronizar el dispositivo Bluetooth %1$s?" "Sí" "No" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index c366629..7387626 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -11,26 +11,20 @@ "Puudutage kiire kasutamiseks" "Sissetulev kiir ..." "Kiir on valmis" - - - - - - + "Kiir ei lõpetanud toimingut" + "Kiir on tühistatud" + "Tühista" "Puudutage vaatamiseks" "Ühendamine" "Ühendatud" - - + "Ühendust ei õnnestunud luua" "Ühenduse katkestamine" "Ühendus on katkestatud" "Ühildamine" - - - - + "Ei saanud ühildada" + "Bluetoothi ei saanud lubada" "Kas soovite kindlasti ühildada Bluetoothi seadme %1$s?" "Jah" "Ei" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 447ca15..92f9461 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -11,26 +11,20 @@ "برای پخش، لمس کنید" "درحال دریافت پرتو..." "پرتو ارسال شد" - - - - - - + "پرتو کامل نشد" + "پرتو لغو شد" + "لغو" "برای مشاهده لمس کنید" "در حال اتصال" "اتصال برقرار شد" - - + "متصل نشد" "در حال قطع اتصال" "اتصال قطع شد" "در حال مرتبط سازی" - - - - + "جفت‌سازی امکانپذیر نیست" + "فعال کردن بلوتوث امکانپذیر نیست" "آیا مطمئن هستید که می‌خواهید دستگاه بلوتوث %1$s را مرتبط کنید؟" "بله" "خیر" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 4d19d53..9235e81 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -11,26 +11,20 @@ "Sentuh untuk menyorot" "Pancaran yang masuk..." "Beam selesai" - - - - - - + "Beam tidak lengkap" + "Beam dibatalkan" + "Batal" "Sentuh untuk melihat" "Menyambungkan" "Tersambung" - - + "Tidak dapat menyambung" "Memutuskan" "Terputus" "Menyandingkan" - - - - + "Tidak dapat menyandingkan" + "Tidak dapat mengaktifkan Bluetooth" "Yakin ingin menyandingkan perangkat Bluetooth %1$s?" "Ya" "Tidak" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 48ea9d2..f70468c 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -18,8 +18,7 @@ "Tocca per visualizzare" - - + "Il dispositivo del destinatario non supporta il trasferimento di file di grandi dimensioni tramite Android Beam." "Collegamento in corso" "Collegato" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 132c046..d7cddaa 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -11,26 +11,20 @@ "공유하기" "수신 빔..." "Beam 완료" - - - - - - + "Beam이 완료되지 않음" + "Beam 취소됨" + "취소" "터치하여 보기" "연결 중" "연결됨" - - + "연결하지 못함" "연결을 끊는 중" "연결 끊김" "페어링 중" - - - - + "페어링하지 못함" + "블루투스를 사용하도록 설정하지 못함" "블루투스 기기 %1$s을(를) 페어링하시겠습니까?" "예" "아니요" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 448f62e..263443a 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -11,26 +11,20 @@ "Jei norite perduoti, palieskite" "Gaunamas perdavimas..." "Perdavimas baigtas" - - - - - - + "Perdavimas nebuvo užbaigtas" + "Perdavimas atšauktas" + "Atšaukti" "Jei norite peržiūrėti, palieskite" "Prisijungiama" "Prisijungta" - - + "Nepavyko prisijungti" "Atsijungiama" "Atsijungta" "Susiejama" - - - - + "Nepavyko susieti" + "Nepavyko įgalinti „Bluetooth“" "Ar tikrai norite susieti „Bluetooth“ įrenginį „%1$s“?" "Taip" "Ne" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 82939a2..e42337f 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -11,26 +11,20 @@ "Pieskarties, lai projicētu" "Ienākošie vienumi, izmantojot funkciju Beam..." "Kopīgošana, izmantojot funkciju Beam, ir pabeigta." - - - - - - + "Kopīgošana, izmantojot funkciju Beam, netika pabeigta" + "Kopīgošana, izmantojot funkciju Beam, atcelta" + "Atcelt" "Pieskarieties, lai skatītu." "Notiek savienojuma izveide" "Savienojums izveidots" - - + "Nevarēja izveidot savienojumu" "Notiek savienojuma pārtraukšana" "Savienojums pārtraukts" "Notiek savienošana pārī" - - - - + "Nevarēja savienot pārī" + "Nevarēja iespējot Bluetooth" "Vai tiešām vēlaties savienot pārī Bluetooth ierīci %1$s?" "Jā" "Nē" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index d5f3163..8f3b659 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -11,26 +11,20 @@ "Sentuh untuk memancarkan" "Pancar sedang masuk..." "Pancar selesai" - - - - - - + "Pancar tidak lengkap" + "Pancar dibatalkan" + "Batal" "Sentuh untuk melihat" "Menyambung" "Disambungkan" - - + "Tidak boleh menyambung" "Memutuskan sambungan" "Diputuskan sambungan" "Menjadikan pasangan" - - - - + "Tidak boleh berpasangan" + "Tidak boleh mendayakan Bluetooth" "Adakah anda pasti anda mahu memadankan peranti Bluetooth %1$s?" "Ya" "Tidak" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 3da2db8..b6a8b7e 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -11,26 +11,20 @@ "Dotknij, aby przesłać" "Odbieram dane zbliżeniowo..." "Przesyłanie zbliżeniowe zakończone" - - - - - - + "Przesyłanie zbliżeniowe nie udało się" + "Przesyłanie zbliżeniowe zostało anulowane" + "Anuluj" "Dotknij, by wyświetlić" "Łączenie" "Połączono" - - + "Nie można nawiązać połączenia" "Rozłączanie" "Rozłączone" "Tworzenie sparowania" - - - - + "Nie można sparować" + "Nie można włączyć Bluetootha" "Czy na pewno chcesz sparować urządzenie Bluetooth %1$s?" "Tak" "Nie" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 7f009e5..eeef95c 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -11,26 +11,20 @@ "Toque para iluminar" "Feixe de entrada..." "Irradiação concluída" - - - - - - + "O feixe não foi concluído" + "Feixe cancelado" + "Cancelar" "Toque para visualizar" "Conectando" "Conectado" - - + "Não foi possível conectar" "Desconectando" "Desconectado" "Pareando" - - - - + "Não foi possível parear" + "Não foi possível ativar o Bluetooth" "Tem certeza de que deseja parear o dispositivo Bluetooth %1$s?" "Sim" "Não" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 2c65adc..ce19a5a 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -11,26 +11,20 @@ "Pindutin upang i-beam" "Dumarating na beam..." "Kumpleto na ang pag-beam" - - - - - - + "Hindi nakumpleto ang beam" + "Kinansela ang beam" + "Kanselahin" "Pindutin upang tingnan" "Kumokonekta" "Nakakonekta" - - + "Hindi makakonekta" "Nagdidiskonekta" "Nadiskonekta" "Pinapares" - - - - + "Hindi makapagpares" + "Hindi mapagana ang Bluetooth" "Sigurado ka bang nais mong ipares ang Bluetooth device na %1$s?" "Oo" "Hindi" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 0086aac..b8df9ba 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -11,26 +11,20 @@ "Торкніться, щоб передати дані" "Вхідне передавання даних..." "Передавання даних виконано" - - - - - - + "Передавання даних не завершено" + "Передавання даних скасовано" + "Скасувати" "Торкніться, щоб переглянути" "Під’єднання" "Під’єднано" - - + "Не вдалося з’єднатись" "Від’єднання" "Від’єднано" "Створення пари" - - - - + "Не вдалося створити пару" + "Не вдалося ввімкнути Bluetooth" "Дійсно створити пару з пристроєм Bluetooth %1$s?" "Так" "Ні" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index c40cc16..700807d 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -11,26 +11,20 @@ "Chạm để truyền" "Tia đến..." "Hoàn tất chiếu" - - - - - - + "Chiếu chưa hoàn tất" + "Chiếu bị hủy" + "Hủy" "Chạm để xem" "Đang kết nối" "Đã kết nối" - - + "Không thể kết nối" "Đang ngắt kết nối" "Đã ngắt kết nối" "Đang ghép nối" - - - - + "Không thể ghép nối" + "Không thể bật Bluetooth" "Bạn có chắc chắn muốn ghép nối thiết bị Bluetooth %1$s không?" "Có" "Không" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 6e34222..a3c366d 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -11,26 +11,20 @@ "Cindezela kwibhimu" "Ukuvumelanisa okungenayo..." "Ukuvumelanisa kuqedile" - - - - - - + "Ukuvumelanisa akuqedile" + "Ukuvumelanisa kukhanseliwe" + "Khansela" "Thinta ukuze ubuke" "Iyaxhuma" "Ixhunyiwe" - - + "Ayikwazanga ukuxhuma" "Iyanqamula" "Inqamukile" "Iyabhangqa" - - - - + "Ayikwazanga ukumatanisa" + "Ayikwazanga ukunika amandla i-Bluetooth" "Ingabe unesiqinisekiso sokuthi ufuna ukuhambisa ngakubili idivayisi %1$s ye-Bluetooth?" "Yebo" "Cha" -- cgit v1.1 From ad8b3e14a528aa74ffa3cfe14ad173ee0d886614 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Thu, 31 May 2012 11:35:54 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Ib98177897b66315752a65ac7b228978a69437cb0 --- res/values-af/strings.xml | 21 +++++++-------------- res/values-am/strings.xml | 3 +-- res/values-ar/strings.xml | 3 +-- res/values-da/strings.xml | 18 ++++++------------ res/values-es/strings.xml | 3 +-- res/values-fr/strings.xml | 3 +-- res/values-it/strings.xml | 18 ++++++------------ res/values-iw/strings.xml | 3 +-- res/values-nl/strings.xml | 3 +-- res/values-pt-rPT/strings.xml | 3 +-- res/values-ru/strings.xml | 18 ++++++------------ res/values-sv/strings.xml | 18 ++++++------------ res/values-sw/strings.xml | 3 +-- res/values-zh-rCN/strings.xml | 20 +++++++------------- res/values-zu/strings.xml | 3 +-- 15 files changed, 47 insertions(+), 93 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 2c32c90..e7e283c 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -11,26 +11,19 @@ "Raak en straal" "Inkomende straal..." "Straling voltooi" - - - - - - + "Straal het nie voltooi nie" + "Straal gekanselleer" + "Kanselleer" "Raak om te bekyk" - - + "Die ontvanger se toestel ondersteun nie groot lêeroordrag via \'n straal nie." "Koppel tans" "Gekoppel" - - + "Kon nie koppel nie" "Ontkoppel tans" "Ontkoppel" "Saambinding" - - - - + "Kon nie saambind nie" + "Kon nie Bluetooth aktiveer nie" "Is jy seker jy wil die Bluetooth-toestel, %1$s, saambind?" "Ja" "Nee" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index aa920d9..f37d647 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -15,8 +15,7 @@ "ሞገድ ተሰርዧል" "ሰርዝ" "ለማየት ንካ" - - + "የተቀባዩ መሣሪያ ትልቅ ፋይል በሞገድ በኩል ማስተላለፍ አይደግፍም።" "በመገናኘት ላይ" "ተገናኝቷል" "ማገናኘት አልተቻለም" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 28ddb1d..d7ec39f 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -15,8 +15,7 @@ "تم إلغاء الشعاع" "إلغاء" "المس ليتم العرض" - - + "جهاز المستلم لا يوفر نقل ملفات كبيرة عبر الشعاع." "جارٍ الاتصال..." "متصل" "تعذر الاتصال" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index b284b5b..d06ed32 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -11,26 +11,20 @@ "Tryk for at overføre" "Indgående overførsel..." "Overførsel fuldført" - - - - - - + "Overførslen blev ikke fuldført" + "Overførslen blev annulleret" + "Annuller" "Tryk for at se" "Opretter forbindelse" "Forbundet" - - + "Der kunne ikke oprettes forbindelse" "Afbryder forbindelse" "Afbrudt" "Parrer" - - - - + "Kunne ikke parres" + "Bluetooth kunne ikke aktiveres" "Er du sikker på du vil parre Bluetooth-enheden %1$s?" "Ja" "Nej" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index d78117c..57d4b6d 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -15,8 +15,7 @@ "Transferencia cancelada" "Cancelar" "Tocar para ver" - - + "El dispositivo del receptor no admite la transferencia de archivos de gran tamaño." "Conectando..." "Conectado" "Error al establecer conexión" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index b7b68d8..334d72b 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -18,8 +18,7 @@ "Appuyer pour afficher" - - + "Le récepteur n\'est pas compatible avec le transfert de fichiers volumineux via le partage." "Connexion en cours…" "Connecté" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index f70468c..d648a73 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -11,25 +11,19 @@ "Tocca per trasmettere" "Trasmissione in arrivo..." "Trasmissione completata" - - - - - - + "Trasmissione non completata" + "Trasmissione annullata" + "Annulla" "Tocca per visualizzare" "Il dispositivo del destinatario non supporta il trasferimento di file di grandi dimensioni tramite Android Beam." "Collegamento in corso" "Collegato" - - + "Impossibile connettersi" "Scollegamento in corso" "Scollegato" "Accoppiamento" - - - - + "Impossibile accoppiare" + "Impossibile attivare il Bluetooth" "Vuoi accoppiare il dispositivo Bluetooth %1$s?" "Sì" "No" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index a777df6..063a5e7 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -15,8 +15,7 @@ "הקרן בוטלה" "ביטול" "גע כדי להציג" - - + "המכשיר המקבל אינו תומך בהעברת קובץ גדול באמצעות קרן." "מתחבר" "מחובר" "לא ניתן להתחבר." diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 1d94a1f..9ab6445 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -18,8 +18,7 @@ "Raak aan om te bekijken" - - + "Het apparaat van de ontvanger ondersteund de overdracht van grote bestanden via beam niet." "Verbinding maken" "Verbonden" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 8bb6520..ce4a8b8 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -18,8 +18,7 @@ "Tocar para ver" - - + "O dispositivo do recetor não suporta a transferência de ficheiros grandes através de partilha." "A ligar" "Ligado" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 0459a11..92406cd 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -11,26 +11,20 @@ "Нажмите, чтобы передать данные" "Получение данных…" "Передача данных завершена" - - - - - - + "Передача данных не завершена" + "Передача данных отменена" + "Отмена" "Нажмите, чтобы просмотреть" "Подключение…" "Подключено" - - + "Не удалось подключиться" "Отключение…" "Отключено" "Подключение…" - - - - + "Не удалось связать" + "Не удалось включить Bluetooth" "Подключить Bluetooth-устройство %1$s?" "Да" "Нет" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 15dbb2d..564466c 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -11,26 +11,20 @@ "Tryck här om du vill överföra" "Inkommande trådlös överföring ..." "Den trådlösa överföringen har slutförts" - - - - - - + "Den trådlösa överföringen slutfördes inte" + "Den trådlösa överföringen avbröts" + "Avbryt" "Tryck och visa" "Anslutningen upprättas" "Anslutningen har upprättats" - - + "Det gick inte att ansluta" "Anslutningen avbryts" "Frånkopplad" "Parkoppling upprättas" - - - - + "Det gick inte att parkoppla" + "Det gick inte att aktivera Bluetooth" "Är du säker på att du vill para ihop Bluetooth-enheten %1$s?" "Ja" "Nej" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 8b0f9d9..843c437 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -15,8 +15,7 @@ "Boriti imeghairiwa" "Ghairi" "Gusa ili utazame" - - + "Kifaa cha upokeaji hakitegemezi uhamishaji wa faili kubwa kupitia kwenye boriti." "Inaunganisha" "Imeunganishwa" "Haikuweza kuunganisha" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index b6fa370..9cc5328 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -9,28 +9,22 @@ "接触可向此人发送您的联系人信息。" "NFC 已启用。" "触摸即可发送" - "正在接受 Beam 发送..." + "正在接收 Beam 内容..." "Beam 发送完毕" - - - - - - + "Beam 发送未完成" + "Beam 发送已取消" + "取消" "触摸即可查看" "正在连接" "已连接" - - + "无法连接" "正在断开连接" "已断开连接" "正在配对" - - - - + "无法配对" + "无法启用蓝牙" "您确定要与蓝牙设备%1$s配对吗?" "是" "否" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index a3c366d..2698bea 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -15,8 +15,7 @@ "Ukuvumelanisa kukhanseliwe" "Khansela" "Thinta ukuze ubuke" - - + "Idivayisi yomamukeli ayisekeli ukuhanjiswa kwamafayela amakhulu ngokuvumelanisa." "Iyaxhuma" "Ixhunyiwe" "Ayikwazanga ukuxhuma" -- cgit v1.1 From 555f21cb4b17a82930972850aa74e88bc17320eb Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Fri, 1 Jun 2012 10:42:31 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I8bab021567a2f4a20b0a29b178c4b815ea75913b --- res/values-be/strings.xml | 21 +++++++-------------- res/values-bg/strings.xml | 3 +-- res/values-ca/strings.xml | 3 +-- res/values-cs/strings.xml | 21 +++++++-------------- res/values-da/strings.xml | 3 +-- res/values-de/strings.xml | 21 +++++++-------------- res/values-el/strings.xml | 3 +-- res/values-es-rUS/strings.xml | 3 +-- res/values-et/strings.xml | 3 +-- res/values-fa/strings.xml | 3 +-- res/values-fi/strings.xml | 21 +++++++-------------- res/values-fr/strings.xml | 18 ++++++------------ res/values-hi/strings.xml | 18 ++++++------------ res/values-hr/strings.xml | 21 +++++++-------------- res/values-hu/strings.xml | 21 +++++++-------------- res/values-in/strings.xml | 3 +-- res/values-ja/strings.xml | 21 +++++++-------------- res/values-ko/strings.xml | 3 +-- res/values-lt/strings.xml | 3 +-- res/values-lv/strings.xml | 3 +-- res/values-nb/strings.xml | 21 +++++++-------------- res/values-nl/strings.xml | 18 ++++++------------ res/values-pl/strings.xml | 3 +-- res/values-pt/strings.xml | 3 +-- res/values-ru/strings.xml | 3 +-- res/values-sk/strings.xml | 21 +++++++-------------- res/values-sl/strings.xml | 21 +++++++-------------- res/values-sr/strings.xml | 21 +++++++-------------- res/values-sv/strings.xml | 3 +-- res/values-th/strings.xml | 3 +-- res/values-tl/strings.xml | 3 +-- res/values-tr/strings.xml | 21 +++++++-------------- res/values-uk/strings.xml | 3 +-- res/values-vi/strings.xml | 3 +-- res/values-zh-rCN/strings.xml | 3 +-- res/values-zh-rTW/strings.xml | 21 +++++++-------------- 36 files changed, 129 insertions(+), 258 deletions(-) diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index c3b355f..b748d04 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -11,26 +11,19 @@ "Краніце, каб перадаць" "Уваходная перадача beam..." "Працэс перадачы Beam завершаны" - - - - - - + "Перадача Beam не завершана" + "Перадача Beam адменена" + "Адмена" "Націсніце, каб прагледзець" - - + "Прылада атрымальніка не падтрымлівае перадачу вялікіх файлаў праз Beam." "Падключэнне" "Падключана" - - + "Збой падключэння" "Адключэнне" "Адключана" "Падлучэнне" - - - - + "Памылка падключэння" + "Не атрымалася ўключыць Bluetooth" "Вы ўпэўнены, што жадаеце падлучыць прыладу Bluetooth %1$s?" "Так" "Не" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 3984657..5365619 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -18,8 +18,7 @@ "Докоснете, за да видите" - - + "Устройството на получателя не поддържа прехвърляне на големи файлове чрез излъчване." "Свързва се" "Има връзка" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index aa0befa..d6e417f 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -15,8 +15,7 @@ "S\'ha desactivat el sensor" "Cancel·la" "Toca per visualitzar" - - + "El dispositiu del receptor no és compatible amb la transferència de fitxers grans mitjançant sensors." "S\'està connectant" "Connectat" "No es pot establir connexió" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 12d1bfd..9c7f3f7 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -11,26 +11,19 @@ "Přenos zahájíte dotykem" "Příchozí přenos..." "Přenos dokončen" - - - - - - + "Přenos nebyl dokončen" + "Přenos byl zrušen" + "Zrušit" "Zobrazte dotykem" - - + "Zařízení příjemce nepodporuje přenos velkých souborů prostřednictvím funkce Beam." "Připojování" "Připojeno" - - + "Nelze připojit" "Odpojování" "Odpojeno" "Párování" - - - - + "Nelze spárovat" + "Bluetooth nelze povolit." "Opravdu chcete spárovat zařízení Bluetooth %1$s?" "Ano" "Ne" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index d06ed32..23a78a8 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -15,8 +15,7 @@ "Overførslen blev annulleret" "Annuller" "Tryk for at se" - - + "Modtagerens enhed understøtter ikke overførsel af store filer via Beam." "Opretter forbindelse" "Forbundet" "Der kunne ikke oprettes forbindelse" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 5c3c821..ed85c7c 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -11,26 +11,19 @@ "Zum Beamen berühren" "Beam wird empfangen..." "Beamen abgeschlossen" - - - - - - + "Beam wurde nicht abgeschlossen." + "Beam abgebrochen" + "Abbrechen" "Zum Anzeigen berühren" - - + "Das Gerät des Empfängers unterstützt die Übertragung großer Dateien durch Beamen nicht." "Verbindung wird hergestellt" "Verbunden" - - + "Verbindung nicht möglich" "Verbindung wird aufgehoben" "Verbindung getrennt" "Pairing erfolgt" - - - - + "Pairing nicht möglich" + "Bluetooth konnte nicht aktiviert werden." "Möchten Sie das Bluetooth-Gerät %1$s wirklich koppeln?" "Ja" "Nein" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index cad1d4b..aeab0c2 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -15,8 +15,7 @@ "Ακύρωση ζεύξης" "Άκυρο" "Αγγίξτε για προβολή" - - + "Η συσκευή του παραλήπτη δεν υποστηρίζει τη μεταφορά μεγάλων αρχείων μέσω ζεύξης." "Σύνδεση" "Συνδέθηκε" "Δεν ήταν δυνατή η σύνδεση" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 16bf63a..9abc3b7 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -15,8 +15,7 @@ "Transferencia cancelada" "Cancelar" "Toca para ver" - - + "El dispositivo del receptor no admite la transferencia de archivos de gran tamaño." "Conectando..." "Conectados" "No se pudo conectar" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 7387626..ae3a4d3 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -15,8 +15,7 @@ "Kiir on tühistatud" "Tühista" "Puudutage vaatamiseks" - - + "Vastuvõtja seade ei toeta suurte failide edastamist kiire kaudu." "Ühendamine" "Ühendatud" "Ühendust ei õnnestunud luua" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 92f9461..2ed982b 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -15,8 +15,7 @@ "پرتو لغو شد" "لغو" "برای مشاهده لمس کنید" - - + "دستگاه گیرنده انتقال فایل‌های بزرگ از طریق پرتو را پشتیبانی نمی کند." "در حال اتصال" "اتصال برقرار شد" "متصل نشد" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index d3252ba..cc41c46 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -11,26 +11,19 @@ "Kosketa palkkia" "Saapuva sisällönjakopyyntö..." "Sisältö jaettu" - - - - - - + "Jakoa ei suoritettu valmiiksi" + "Jako peruutettu" + "Peruuta" "Kosketa ja näytä" - - + "Vastaanottajan laite ei tue suurten tiedostojen siirtoa sisällön jakamisen kautta." "Yhdistetään" "Yhdistetty" - - + "Ei yhteyttä" "Katkaistaan yhteyttä" "Yhteys katkaistu" "Laiteparia muodostetaan" - - - - + "Laiteparia ei voi muodostaa" + "Bluetooth-yhteyttä ei voi ottaa käyttöön" "Oletko varma, että haluat muodostaa laiteparin Bluetooth-laitteeseen %1$s?" "Kyllä" "Ei" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 334d72b..c0d92b2 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -11,25 +11,19 @@ "Appuyer pour partager" "Partage entrant..." "Partage terminé." - - - - - - + "Échec du partage." + "Partage annulé." + "Annuler" "Appuyer pour afficher" "Le récepteur n\'est pas compatible avec le transfert de fichiers volumineux via le partage." "Connexion en cours…" "Connecté" - - + "Impossible d’établir la connexion." "Déconnexion en cours…" "Déconnecté" "Association en cours…" - - - - + "Impossible d\'effectuer l\'association." + "Impossible d\'activer le Bluetooth." "Voulez-vous vraiment associer l\'appareil Bluetooth %1$s ?" "Oui" "Non" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 22ac17b..56f5e5f 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -11,26 +11,20 @@ "बीम करने के लिए स्पर्श करें" "इनकमिंग बीम..." "बीम करना पूर्ण" - - - - - - + "बीम पूर्ण नहीं हुआ" + "बीम रद्द" + "रद्द करें" "देखने के लिए स्‍पर्श करें" "कनेक्ट हो रहा है" "कनेक्ट है" - - + "कनेक्‍ट नहीं किया जा सका" "डिस्कनेक्ट कर रहा है" "डिस्कनेक्ट किया गया" "युग्मन" - - - - + "युग्‍मित नहीं किया जा सका" + "Bluetooth को सक्षम नहीं किया जा सका" "क्‍या आप वाकई Bluetooth उपकरण %1$s को युग्मित करना चाहते हैं?" "हां" "नहीं" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 6ac252b..c9e5842 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -11,26 +11,19 @@ "Dodirnite za emitiranje" "Dolazno emitiranje..." "Emitiranje je završeno" - - - - - - + "Emitiranje nije dovršeno" + "Emitiranje otkazano" + "Odustani" "Dodirnite za prikaz" - - + "Uređaj prijamnika ne podržava prijenos velikih datoteka putem emitiranja." "Povezivanje" "Povezan" - - + "Spajanje nije bilo moguće" "Prekid veze" "Prekinuta veza" "Uparivanje" - - - - + "Uparivanje nije bilo moguće" + "Omogućavanje Bluetootha nije bilo moguće" "Jeste li sigurni da želite upariti Bluetooth uređaj %1$s?" "Da" "Ne" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 2803945..fba3b78 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -11,26 +11,19 @@ "Érintse meg a sugárzáshoz" "Bejövő sugár..." "Átvitel befejezve." - - - - - - + "A sugárzás nem fejeződött be" + "Sugárzás megszakítva" + "Mégse" "A megtekintéshez érintse meg." - - + "A fogadó eszköz nem támogatja a nagyméretű fájlok átvitelét adatsugárzás útján." "Csatlakozás" "Csatlakozva" - - + "A kapcsolódás sikertelen" "Szétkapcsolás" "Szétkapcsolva" "Párosítás" - - - - + "Nem sikerült a párosítás" + "Nem lehet aktiválni a Bluetootht" "Biztosan párosítani szeretné a(z) %1$s Bluetooth-eszközt?" "Igen" "Nem" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 9235e81..b876dc7 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -15,8 +15,7 @@ "Beam dibatalkan" "Batal" "Sentuh untuk melihat" - - + "Perangkat penerima tidak mendukung transfer file besar melalui beam." "Menyambungkan" "Tersambung" "Tidak dapat menyambung" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index a0c15bd..87f9656 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -11,26 +11,19 @@ "タップしてビーム" "ビームを受信しています..." "ビーム完了" - - - - - - + "ビームが完了しませんでした" + "ビームをキャンセルしました" + "キャンセル" "タップして表示" - - + "受信側の端末は、ビームを介す大量のファイル転送をサポートしていません。" "接続中" "接続されました" - - + "接続できませんでした" "切断中" "切断されました" "ペア設定" - - - - + "ペア設定できませんでした" + "Bluetoothを有効にできませんでした" "Bluetoothデバイス%1$sをペアに設定してもよろしいですか?" "はい" "いいえ" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index d7cddaa..1ba5703 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -15,8 +15,7 @@ "Beam 취소됨" "취소" "터치하여 보기" - - + "수신자의 기기는 빔을 통한 대용량 파일 전송을 지원하지 않습니다." "연결 중" "연결됨" "연결하지 못함" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 263443a..06ac189 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -15,8 +15,7 @@ "Perdavimas atšauktas" "Atšaukti" "Jei norite peržiūrėti, palieskite" - - + "Gavėjo įrenginyje nepalaikomas didelio failo perdavimas naudojant perdavimo funkciją." "Prisijungiama" "Prisijungta" "Nepavyko prisijungti" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index e42337f..0eb9883 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -15,8 +15,7 @@ "Kopīgošana, izmantojot funkciju Beam, atcelta" "Atcelt" "Pieskarieties, lai skatītu." - - + "Saņēmēja ierīce neatbalsta lielu failu pārsūtīšanu, izmantojot funkciju Beam." "Notiek savienojuma izveide" "Savienojums izveidots" "Nevarēja izveidot savienojumu" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 2d294db..3380006 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -11,26 +11,19 @@ "Berør for å overføre trådløst" "Innkommende trådløs overføring" "Overføring fullført" - - - - - - + "Overføringen ble ikke fullført" + "Overføringen ble avbrutt" + "Avbryt" "Trykk for å se" - - + "Mottakerens enhet støtter ikke store filoverføringer via Android Beam." "Kobler til" "Tilkoblet" - - + "Kunne ikke koble til" "Frakobler" "Frakoblet" "Kobler til" - - - - + "Kunne ikke koble til" + "Kunne ikke aktivere Bluetooth" "Er du sikker på at koble til Bluetooth-enheten %1$s?" "Ja" "Nei" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 9ab6445..cfb3ab8 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -11,25 +11,19 @@ "Tikken om uit te zenden" "Inkomende beam..." "Beam voltooid" - - - - - - + "Beam niet voltooid" + "Beam geannuleerd" + "Annuleren" "Raak aan om te bekijken" "Het apparaat van de ontvanger ondersteund de overdracht van grote bestanden via beam niet." "Verbinding maken" "Verbonden" - - + "Kan niet verbinden" "Loskoppelen" "Losgekoppeld" "Koppelen" - - - - + "Kan niet koppelen" + "Kan Bluetooth niet inschakelen" "Weet u zeker dat u het Bluetooth-apparaat %1$s wilt koppelen?" "Ja" "Nee" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index b6a8b7e..e7095e8 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -15,8 +15,7 @@ "Przesyłanie zbliżeniowe zostało anulowane" "Anuluj" "Dotknij, by wyświetlić" - - + "Urządzenie odbierające nie pozwala na przesyłanie dużych plików zbliżeniowo." "Łączenie" "Połączono" "Nie można nawiązać połączenia" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index eeef95c..fed4fbf 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -15,8 +15,7 @@ "Feixe cancelado" "Cancelar" "Toque para visualizar" - - + "O dispositivo receptor não suporta a transferência de arquivos grandes através do feixe." "Conectando" "Conectado" "Não foi possível conectar" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 92406cd..e2caaa0 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -15,8 +15,7 @@ "Передача данных отменена" "Отмена" "Нажмите, чтобы просмотреть" - - + "Устройство получателя не поддерживает передачу больших объемов данных через Android Beam." "Подключение…" "Подключено" "Не удалось подключиться" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index a400c01..21ab94a 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -11,26 +11,19 @@ "Dotykom spustíte prenos" "Prichádzajúci prenos..." "Prenos bol dokončený" - - - - - - + "Prenos nebol dokončený" + "Prenos bol zrušený" + "Zrušiť" "Zobrazte dotykom" - - + "Zariadenie príjemcu nepodporuje prenos veľkých súborov prostredníctvom funkcie Beam." "Prebieha pripájanie" "Pripojené" - - + "Nepodarilo sa pripojiť" "Prebieha odpájanie" "Odpojené" "Prebieha párovanie" - - - - + "Nie je možné spárovať" + "Bluetooth sa nepodarilo povoliť" "Naozaj chcete spárovať zariadenie Bluetooth %1$s?" "Áno" "Nie" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 67e4786..7e2bf31 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -11,26 +11,19 @@ "Dotaknite se, da pošljete" "Dohodni prenos ..." "Prenos končan" - - - - - - + "Prenos se ni končal" + "Prenos je preklican" + "Prekliči" "Dotaknite se za prikaz" - - + "Prejemnikova naprava ne podpira prenosa velikih datotek prek funkcije Android Beam." "Vzpostavljanje povezave" "Povezano" - - + "Povezava ni mogoča" "Prekinjanje povezave" "Ni povezave" "Seznanjanje" - - - - + "Seznanitev ni mogoča" + "Bluetootha ni mogoče omogočiti" "Ste prepričani, da želite seznaniti napravo Bluetooth %1$s?" "Da" "Ne" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 859f0dd..0b0f229 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -11,26 +11,19 @@ "Додирните за емитовање" "Долазно пребацивање..." "Пребацивање је довршено" - - - - - - + "Пребацивање се није завршило" + "Пребацивање је отказано" + "Откажи" "Додирните да бисте прегледали" - - + "Уређај пријемника не подржава пренос великих датотека пребацивањем." "Повезивање" "Повезано" - - + "Повезивање није могуће" "Прекидање везе" "Веза је прекинута" "Упаривање" - - - - + "Упаривање није могуће" + "Није могуће омогућити Bluetooth" "Да ли сте сигурни да желите да упарите Bluetooth уређај %1$s?" "Да" "Не" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 564466c..14c701c 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -15,8 +15,7 @@ "Den trådlösa överföringen avbröts" "Avbryt" "Tryck och visa" - - + "Mottagarens enheten stöder inte trådlös överföring av stora filer." "Anslutningen upprättas" "Anslutningen har upprättats" "Det gick inte att ansluta" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 075744a..ccacf94 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -15,8 +15,7 @@ "ยกเลิกบีมแล้ว" "ยกเลิก" "แตะเพื่อดู" - - + "อุปกรณ์ของผู้รับไม่สนับสนุนการถ่ายโอนไฟล์ขนาดใหญ่ผ่านการบีม" "กำลังเชื่อมต่อ" "เชื่อมต่อแล้ว" "เชื่อมต่อไม่ได้" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index ce19a5a..86a2ef7 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -15,8 +15,7 @@ "Kinansela ang beam" "Kanselahin" "Pindutin upang tingnan" - - + "Hindi sinusuportahan ng device ng receiver ang malaking paglipat ng file sa pamamagitan ng beam." "Kumokonekta" "Nakakonekta" "Hindi makakonekta" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index a9169cc..f2306e9 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -11,26 +11,19 @@ "Göndermek için dokunun" "Gelen ışın..." "Işınlama tamamlandı" - - - - - - + "Işınlama tamamlanmadı" + "Işınlama iptal edildi" + "İptal" "Görüntülemek için dokunun" - - + "Alıcının cihazı yüksek boyutlu dosyaların ışınlamayla aktarılmasını desteklemiyor." "Bağlanıyor" "Bağlandı" - - + "Bağlantı kurulamadı" "Bağlantı kesiliyor" "Bağlantı kesildi" "Eşleştiriliyor" - - - - + "Eşleştirilemedi" + "Bluetooth etkinleştirilemedi" "%1$s adlı Bluetooth cihazını eşleştirmek istediğinizden emin misiniz?" "Evet" "Hayır" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index b8df9ba..0bb6aac 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -15,8 +15,7 @@ "Передавання даних скасовано" "Скасувати" "Торкніться, щоб переглянути" - - + "Пристрій отримувача не підтримує пересилання великих файлів за допомогою функції Передавання даних Android." "Під’єднання" "Під’єднано" "Не вдалося з’єднатись" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 700807d..5f887fc 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -15,8 +15,7 @@ "Chiếu bị hủy" "Hủy" "Chạm để xem" - - + "Thiết bị của người nhận không hỗ trợ truyền tệp lớn qua quá trình chiếu." "Đang kết nối" "Đã kết nối" "Không thể kết nối" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 9cc5328..2cd45ae 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -15,8 +15,7 @@ "Beam 发送已取消" "取消" "触摸即可查看" - - + "接收者的设备不支持通过 Beam 传输较大的文件。" "正在连接" "已连接" "无法连接" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 5e91881..16d16ec 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -11,26 +11,19 @@ "輕觸即可傳輸" "正在接收傳輸..." "傳輸完成" - - - - - - + "傳輸未完成" + "傳輸已取消" + "取消" "輕觸即可查看" - - + "接收者的裝置不支援透過 Beam 傳輸大型檔案。" "連線中" "已連線" - - + "無法連線" "正在中斷連線" "已中斷連線" "配對中" - - - - + "無法配對" + "無法啟用藍牙" "您確定要與藍牙裝置「%1$s」配對嗎?" "是" "否" -- cgit v1.1 From fd571698ea889b1acb03dd17358bfb539f52b7fa Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Mon, 4 Jun 2012 16:31:45 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Ia30d6af598d859cd1533e8942681a4e664217177 --- res/values-bg/strings.xml | 18 ++++++------------ res/values-ja/strings.xml | 2 +- res/values-pt-rPT/strings.xml | 18 ++++++------------ 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 5365619..3514983 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -11,25 +11,19 @@ "Докоснете, за да излъчите" "Входящо излъчване..." "Излъчването завърши" - - - - - - + "Излъчването не завърши" + "Излъчването бе анулирано" + "Отказ" "Докоснете, за да видите" "Устройството на получателя не поддържа прехвърляне на големи файлове чрез излъчване." "Свързва се" "Има връзка" - - + "Не можа да се установи връзка" "Изключва се" "Изключено" "Извършва се сдвояване" - - - - + "Не можа да се сдвои" + "Bluetooth не можа да се активира" "Наистина ли искате да сдвоите устройството с Bluetooth %1$s?" "Да" "Не" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 87f9656..afd6997 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -15,7 +15,7 @@ "ビームをキャンセルしました" "キャンセル" "タップして表示" - "受信側の端末は、ビームを介す大量のファイル転送をサポートしていません。" + "受信側の端末は、ビーム経由のサイズの大きなファイルの転送をサポートしていません。" "接続中" "接続されました" "接続できませんでした" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index ce4a8b8..3ff9d20 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -11,25 +11,19 @@ "Toque para transmitir" "A receber partilha..." "Partilha concluída" - - - - - - + "A partilha não foi concluída" + "Partilha cancelada" + "Cancelar" "Tocar para ver" "O dispositivo do recetor não suporta a transferência de ficheiros grandes através de partilha." "A ligar" "Ligado" - - + "Não foi possível ligar" "A desligar" "Desligado" "A sincronizar" - - - - + "Não foi possível emparelhar" + "Não foi possível ativar o Bluetooth" "Tem a certeza de que pretende sincronizar o dispositivo Bluetooth %1$s?" "Sim" "Não" -- cgit v1.1 From 57065aae3bf6beca33230e5e4082701b9001dfb8 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Tue, 5 Jun 2012 10:03:47 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I7045888f5b91b62f0bac53e917ce4d6df982bfc7 --- res/values-nl/strings.xml | 2 +- res/values-ru/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index cfb3ab8..7b62289 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -15,7 +15,7 @@ "Beam geannuleerd" "Annuleren" "Raak aan om te bekijken" - "Het apparaat van de ontvanger ondersteund de overdracht van grote bestanden via beam niet." + "Het apparaat van de ontvanger ondersteunt de overdracht van grote bestanden via beam niet." "Verbinding maken" "Verbonden" "Kan niet verbinden" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index e2caaa0..1d466fc 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -22,7 +22,7 @@ "Отключение…" "Отключено" "Подключение…" - "Не удалось связать" + "Не удалось установить связь" "Не удалось включить Bluetooth" "Подключить Bluetooth-устройство %1$s?" "Да" -- cgit v1.1 From a4de0c04ae3cac0dc26acf7a6eb3656a3d07e7fd Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Wed, 6 Jun 2012 11:23:41 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I6414a27f17b7d16666f870779b7eab7577043a55 --- res/values-ca/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index d6e417f..591776a 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -18,7 +18,7 @@ "El dispositiu del receptor no és compatible amb la transferència de fitxers grans mitjançant sensors." "S\'està connectant" "Connectat" - "No es pot establir connexió" + "No es pot establir la connexió" "S\'està desconnectant" "Desconnectat" "Sincronització" -- cgit v1.1 From 41c57c394d7ef5a2b435f7bb1561bfc7e5ac5012 Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Thu, 7 Jun 2012 13:15:56 -0700 Subject: Import translations. DO NOT MERGE Change-Id: If983e489c3d470cb44662dd1d0ed8f2662becaee --- res/values-hr/strings.xml | 2 +- res/values-pl/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index c9e5842..52baa21 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -15,7 +15,7 @@ "Emitiranje otkazano" "Odustani" "Dodirnite za prikaz" - "Uređaj prijamnika ne podržava prijenos velikih datoteka putem emitiranja." + "Uređaj prijamnika ne podržava prijenos velikih datoteka emitiranjem." "Povezivanje" "Povezan" "Spajanje nije bilo moguće" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index e7095e8..89c115f 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -15,7 +15,7 @@ "Przesyłanie zbliżeniowe zostało anulowane" "Anuluj" "Dotknij, by wyświetlić" - "Urządzenie odbierające nie pozwala na przesyłanie dużych plików zbliżeniowo." + "Urządzenie odbierające nie pozwala na zbliżeniowe przesyłanie dużych plików." "Łączenie" "Połączono" "Nie można nawiązać połączenia" -- cgit v1.1 From ebb3ea0cab433ee8f19ccd95767df2b666474acd Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Mon, 11 Jun 2012 10:55:56 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I2d9b6ca3da84f177a91f50881267e577f276fc51 --- res/values-es-rUS/strings.xml | 8 ++++---- res/values-ms/strings.xml | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 9abc3b7..5326009 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -11,8 +11,8 @@ "Tocar para transmitir" "Transmisión entrante..." "Transmisión completa" - "La transferencia no se completó" - "Transferencia cancelada" + "La transmisión no se completó" + "Transmisión cancelada" "Cancelar" "Toca para ver" "El dispositivo del receptor no admite la transferencia de archivos de gran tamaño." @@ -22,8 +22,8 @@ "Desconectando..." "Desconectados" "Sincronizando..." - "No se pudo vincular" - "Error al habilitar Bluetooth" + "No se pudo sincronizar" + "Error al activar Bluetooth" "¿Realmente deseas sincronizar el dispositivo Bluetooth %1$s?" "Sí" "No" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index 8f3b659..7e53ff3 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -15,16 +15,15 @@ "Pancar dibatalkan" "Batal" "Sentuh untuk melihat" - - + "Peranti penerima tidak menyokong pemindahan fail besar melalui pancaran." "Menyambung" "Disambungkan" - "Tidak boleh menyambung" + "Tidak dapat menyambung" "Memutuskan sambungan" "Diputuskan sambungan" "Menjadikan pasangan" - "Tidak boleh berpasangan" - "Tidak boleh mendayakan Bluetooth" + "Tidak dapat berpasangan" + "Tidak dapat mendayakan Bluetooth" "Adakah anda pasti anda mahu memadankan peranti Bluetooth %1$s?" "Ya" "Tidak" -- cgit v1.1 From 8eb7b1f8bac35b4d253399ceac8d253db9a2b84c Mon Sep 17 00:00:00 2001 From: Eric Fischer Date: Wed, 13 Jun 2012 10:40:23 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Id967dca7145ac067115d6d4acebf7cda8aaf3df2 --- res/values-sw/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 843c437..803e616 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -15,7 +15,7 @@ "Boriti imeghairiwa" "Ghairi" "Gusa ili utazame" - "Kifaa cha upokeaji hakitegemezi uhamishaji wa faili kubwa kupitia kwenye boriti." + "Kifaa cha upokeaji hakihimili uhamishaji wa faili kubwa kupitia kwenye boriti." "Inaunganisha" "Imeunganishwa" "Haikuweza kuunganisha" -- cgit v1.1 From f6c96ac594edd8480450c391c218c62334424923 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 18 Jun 2012 11:05:10 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Ie2f324b239d1ad183a5b1ad6d481b8eeb3af2ef5 --- res/values-sw/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 803e616..a337161 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -23,7 +23,7 @@ "Imekata muunganisho" "Kuoanisha" "Haikuweza kuoanisha" - "Haikuweza kuwawezesha Bluetooth" + "Haikuweza kuwezesha Bluetooth" "Una uhakika unataka kuoanisha kifaa cha Bluetooth cha %1$s?" "Ndiyo" "Hapana" -- cgit v1.1 From 78499451d20ff198f524c579b6a8b9e43932eb72 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Fri, 13 Jul 2012 11:03:41 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Ied71d51ae286e440cf16f41488f359d6468455da Auto-generated-cl: translation import --- res/values-fa/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 2ed982b..80e1e6a 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -4,18 +4,18 @@ "سرویس Nfc" "Nfc" "مخاطب از طریق NFC دریافت شد" - "برای افزودن این فرد بعنوان یک مخاطب، لمس کنید." + "برای افزودن این فرد به‌عنوان یک مخاطب، لمس کنید." "تعامل NFC کامل شد" "لمس کنید تا اطلاعات تماس خود را به این فرد بدهید." "با NFC فعال شده." "برای پخش، لمس کنید" - "درحال دریافت پرتو..." + "در حال دریافت پرتو..." "پرتو ارسال شد" "پرتو کامل نشد" "پرتو لغو شد" "لغو" "برای مشاهده لمس کنید" - "دستگاه گیرنده انتقال فایل‌های بزرگ از طریق پرتو را پشتیبانی نمی کند." + "دستگاه گیرنده انتقال فایل‌های بزرگ از طریق پرتو را پشتیبانی نمی‌کند." "در حال اتصال" "اتصال برقرار شد" "متصل نشد" -- cgit v1.1 From f5a196b643c654c7ea98a5e2935e3bff6683399b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 11 Jul 2012 12:24:11 -0700 Subject: Implement connection handover LLCP service. The Connection Handover specification dictates that we should exchange Hr/Hs records over a dedicated LLCP service. This adds the service, and starts using it by default. It will fall back to the SNEP GET method to remain compatible with Android 4.1 devices. SNEP GET on these devices will return "Not Implemented", also per the SNEP spec. Also fixed a bug in endianness of the OOB record. Bug: 6759842 Change-Id: Iafe67ab119e933df5dfa0a5645a95bc59badd8ae --- src/com/android/nfc/P2pLinkManager.java | 36 +++- .../android/nfc/handover/BluetoothOppHandover.java | 18 +- .../nfc/handover/ConfirmConnectActivity.java | 16 ++ src/com/android/nfc/handover/HandoverClient.java | 104 +++++++++ src/com/android/nfc/handover/HandoverManager.java | 8 +- src/com/android/nfc/handover/HandoverServer.java | 239 +++++++++++++++++++++ 6 files changed, 414 insertions(+), 7 deletions(-) create mode 100644 src/com/android/nfc/handover/HandoverClient.java create mode 100644 src/com/android/nfc/handover/HandoverServer.java diff --git a/src/com/android/nfc/P2pLinkManager.java b/src/com/android/nfc/P2pLinkManager.java index 189b560..253ddaf 100755 --- a/src/com/android/nfc/P2pLinkManager.java +++ b/src/com/android/nfc/P2pLinkManager.java @@ -17,7 +17,9 @@ package com.android.nfc; import com.android.nfc.echoserver.EchoServer; +import com.android.nfc.handover.HandoverClient; import com.android.nfc.handover.HandoverManager; +import com.android.nfc.handover.HandoverServer; import com.android.nfc.ndefpush.NdefPushClient; import com.android.nfc.ndefpush.NdefPushServer; import com.android.nfc.snep.SnepClient; @@ -123,6 +125,7 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba // TODO dynamically assign SAP values static final int NDEFPUSH_SAP = 0x10; + static final int HANDOVER_SAP = 0x14; static final int LINK_DEBOUNCE_MS = 750; @@ -155,6 +158,7 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba final NdefPushServer mNdefPushServer; final SnepServer mDefaultSnepServer; + final HandoverServer mHandoverServer; final EchoServer mEchoServer; final ActivityManager mActivityManager; final PackageManager mPackageManager; @@ -178,6 +182,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba public P2pLinkManager(Context context, HandoverManager handoverManager) { mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); mDefaultSnepServer = new SnepServer(mDefaultSnepCallback); + mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback); + if (ECHOSERVER_ENABLED) { mEchoServer = new EchoServer(); } else { @@ -206,12 +212,14 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba if (!mIsReceiveEnabled && receiveEnable) { mDefaultSnepServer.start(); mNdefPushServer.start(); + mHandoverServer.start(); if (mEchoServer != null) { mHandler.sendEmptyMessage(MSG_START_ECHOSERVER); } } else if (mIsReceiveEnabled && !receiveEnable) { mDefaultSnepServer.stop(); mNdefPushServer.stop(); + mHandoverServer.stop(); if (mEchoServer != null) { mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER); } @@ -465,11 +473,20 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba try { if (uris != null) { + HandoverClient handoverClient = new HandoverClient(); + NdefMessage response = null; NdefMessage request = handoverManager.createHandoverRequestMessage(); if (request != null) { - SnepMessage snepResponse = snepClient.get(request); - response = snepResponse.getNdefMessage(); + response = handoverClient.sendHandoverRequest(request); + + if (response == null) { + // Remote device may not support handover service, + // try the (deprecated) SNEP GET implementation + // for devices running Android 4.1 + SnepMessage snepResponse = snepClient.get(request); + response = snepResponse.getNdefMessage(); + } } // else, handover not supported if (response != null) { handoverManager.doHandoverUri(uris, response); @@ -495,6 +512,13 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba return SNEP_FAILURE; } + final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { + @Override + public void onHandoverRequestReceived() { + onReceiveHandover(); + } + }; + final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { @Override public void onMessageReceived(NdefMessage msg) { @@ -511,13 +535,17 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba @Override public SnepMessage doGet(int acceptableLength, NdefMessage msg) { + // The NFC Forum Default SNEP server is not allowed to respond to + // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, + // since Android 4.1 used the NFC Forum default server to + // implement connection handover, we will support this + // until we can deprecate it. NdefMessage response = mHandoverManager.tryHandoverRequest(msg); - if (response != null) { onReceiveHandover(); return SnepMessage.getSuccessResponse(response); } else { - return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_FOUND); + return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); } } }; diff --git a/src/com/android/nfc/handover/BluetoothOppHandover.java b/src/com/android/nfc/handover/BluetoothOppHandover.java index ece6a7b..ceb3c62 100644 --- a/src/com/android/nfc/handover/BluetoothOppHandover.java +++ b/src/com/android/nfc/handover/BluetoothOppHandover.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.nfc.handover; import android.bluetooth.BluetoothAdapter; @@ -33,7 +49,7 @@ public class BluetoothOppHandover implements Handler.Callback { static final int MSG_START_SEND = 0; - static final int REMOTE_BT_ENABLE_DELAY_MS = 3000; + static final int REMOTE_BT_ENABLE_DELAY_MS = 5000; static final String ACTION_HANDOVER_SEND = "android.btopp.intent.action.HANDOVER_SEND"; diff --git a/src/com/android/nfc/handover/ConfirmConnectActivity.java b/src/com/android/nfc/handover/ConfirmConnectActivity.java index 22d518f..35a7da1 100644 --- a/src/com/android/nfc/handover/ConfirmConnectActivity.java +++ b/src/com/android/nfc/handover/ConfirmConnectActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.nfc.handover; import android.app.Activity; diff --git a/src/com/android/nfc/handover/HandoverClient.java b/src/com/android/nfc/handover/HandoverClient.java new file mode 100644 index 0000000..86cd23b --- /dev/null +++ b/src/com/android/nfc/handover/HandoverClient.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.nfc.handover; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.util.Log; + +import com.android.nfc.LlcpException; +import com.android.nfc.NfcService; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +public final class HandoverClient { + private static final String TAG = "HandoverClient"; + private static final int MIU = 128; + // Max NDEF length to receive for Hr/Hs messages + private static final boolean DBG = false; + + public NdefMessage sendHandoverRequest(NdefMessage msg) { + if (msg == null) return null; + + NfcService service = NfcService.getInstance(); + + LlcpSocket sock = null; + int offset = 0; + byte[] buffer = msg.toByteArray(); + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + + try { + sock = service.createLlcpSocket(0, MIU, 1, 1024); + if (sock == null) { + throw new IOException("Could not connect to socket."); + } + if (DBG) Log.d(TAG, "about to connect to service " + + HandoverServer.HANDOVER_SERVICE_NAME); + sock.connectToService(HandoverServer.HANDOVER_SERVICE_NAME); + + int remoteMiu = sock.getRemoteMiu(); + if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message"); + while (offset < buffer.length) { + int length = Math.min(buffer.length - offset, remoteMiu); + byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length); + if (DBG) Log.d(TAG, "about to send a " + length + " byte packet"); + sock.send(tmpBuffer); + offset += length; + } + + // Now, try to read back the SNEP response + byte[] partial = new byte[sock.getLocalMiu()]; + NdefMessage handoverSelectMsg = null; + while (true) { + int size = sock.receive(partial); + if (size < 0) { + break; + } + byteStream.write(partial, 0, size); + try { + handoverSelectMsg = new NdefMessage(byteStream.toByteArray()); + // If we get here, message is complete + break; + } catch (FormatException e) { + // Ignore, and try to fetch more bytes + } + } + return handoverSelectMsg; + } catch (IOException e) { + if (DBG) Log.d(TAG, "couldn't connect to handover service"); + } catch (LlcpException e) { + if (DBG) Log.d(TAG, "couldn't connect to handover service"); + } finally { + if (sock != null) { + try { + if (DBG) Log.d(TAG, "about to close"); + sock.close(); + } catch (IOException e) { + // Ignore + } + } + try { + byteStream.close(); + } catch (IOException e) { + // Ignore + } + } + return null; + } +} diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index 9836cdc..51b123c 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -657,8 +657,12 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, NdefRecord createBluetoothOobDataRecord() { byte[] payload = new byte[8]; - payload[0] = 0; - payload[1] = (byte)payload.length; + // Note: this field should be little-endian per the BTSSP spec + // The Android 4.1 implementation used big-endian order here. + // No single Android implementation has ever interpreted this + // length field when parsing this record though. + payload[0] = (byte) (payload.length & 0xFF); + payload[1] = (byte) ((payload.length >> 8) & 0xFF); synchronized (HandoverManager.this) { if (mLocalBluetoothAddress == null) { diff --git a/src/com/android/nfc/handover/HandoverServer.java b/src/com/android/nfc/handover/HandoverServer.java new file mode 100644 index 0000000..e789387 --- /dev/null +++ b/src/com/android/nfc/handover/HandoverServer.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.nfc.handover; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.util.Log; + +import com.android.nfc.LlcpException; +import com.android.nfc.NfcService; +import com.android.nfc.DeviceHost.LlcpServerSocket; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +public final class HandoverServer { + public static final String HANDOVER_SERVICE_NAME = "urn:nfc:sn:handover"; + public static final String TAG = "HandoverServer"; + public static final Boolean DBG = false; + + public static final int MIU = 128; + + final HandoverManager mHandoverManager; + final int mSap; + final Callback mCallback; + + ServerThread mServerThread = null; + boolean mServerRunning = false; + + public interface Callback { + void onHandoverRequestReceived(); + } + + public HandoverServer(int sap, HandoverManager manager, Callback callback) { + mSap = sap; + mHandoverManager = manager; + mCallback = callback; + } + + public synchronized void start() { + if (mServerThread == null) { + mServerThread = new ServerThread(); + mServerThread.start(); + mServerRunning = true; + } + } + + public synchronized void stop() { + if (mServerThread != null) { + mServerThread.shutdown(); + mServerThread = null; + mServerRunning = false; + } + } + + private class ServerThread extends Thread { + private boolean mThreadRunning = true; + LlcpServerSocket mServerSocket; + + @Override + public void run() { + boolean threadRunning; + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + + while (threadRunning) { + try { + synchronized (HandoverServer.this) { + mServerSocket = NfcService.getInstance().createLlcpServerSocket(mSap, + HANDOVER_SERVICE_NAME, MIU, 1, 1024); + } + if (mServerSocket == null) { + if (DBG) Log.d(TAG, "failed to create LLCP service socket"); + return; + } + if (DBG) Log.d(TAG, "created LLCP service socket"); + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + + while (threadRunning) { + LlcpServerSocket serverSocket; + synchronized (HandoverServer.this) { + serverSocket = mServerSocket; + } + + if (serverSocket == null) { + if (DBG) Log.d(TAG, "Server socket shut down."); + return; + } + if (DBG) Log.d(TAG, "about to accept"); + LlcpSocket communicationSocket = serverSocket.accept(); + if (DBG) Log.d(TAG, "accept returned " + communicationSocket); + if (communicationSocket != null) { + new ConnectionThread(communicationSocket).start(); + } + + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + } + if (DBG) Log.d(TAG, "stop running"); + } catch (LlcpException e) { + Log.e(TAG, "llcp error", e); + } catch (IOException e) { + Log.e(TAG, "IO error", e); + } finally { + synchronized (HandoverServer.this) { + if (mServerSocket != null) { + if (DBG) Log.d(TAG, "about to close"); + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; + } + } + } + + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + } + } + + public void shutdown() { + synchronized (HandoverServer.this) { + mThreadRunning = false; + if (mServerSocket != null) { + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; + } + } + } + } + + private class ConnectionThread extends Thread { + private final LlcpSocket mSock; + + ConnectionThread(LlcpSocket socket) { + super(TAG); + mSock = socket; + } + + @Override + public void run() { + if (DBG) Log.d(TAG, "starting connection thread"); + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + + try { + boolean running; + synchronized (HandoverServer.this) { + running = mServerRunning; + } + + byte[] partial = new byte[mSock.getLocalMiu()]; + + NdefMessage handoverRequestMsg = null; + while (running) { + int size = mSock.receive(partial); + if (size < 0) { + break; + } + byteStream.write(partial, 0, size); + // 1) Try to parse a handover request message from bytes received so far + try { + handoverRequestMsg = new NdefMessage(byteStream.toByteArray()); + } catch (FormatException e) { + // Ignore, and try to fetch more bytes + } + + if (handoverRequestMsg != null) { + // 2) convert to handover response + NdefMessage resp = mHandoverManager.tryHandoverRequest(handoverRequestMsg); + if (resp == null) { + Log.e(TAG, "Failed to create handover response"); + break; + } + + // 3) send handover response + int offset = 0; + byte[] buffer = resp.toByteArray(); + int remoteMiu = mSock.getRemoteMiu(); + while (offset < buffer.length) { + int length = Math.min(buffer.length - offset, remoteMiu); + byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length); + mSock.send(tmpBuffer); + offset += length; + } + // We're done + mCallback.onHandoverRequestReceived(); + break; + } + + synchronized (HandoverServer.this) { + running = mServerRunning; + } + } + + } catch (IOException e) { + if (DBG) Log.d(TAG, "IOException"); + } finally { + try { + if (DBG) Log.d(TAG, "about to close"); + mSock.close(); + } catch (IOException e) { + // ignore + } + try { + byteStream.close(); + } catch (IOException e) { + // ignore + } + } + if (DBG) Log.d(TAG, "finished connection thread"); + } + } +} -- cgit v1.1 From 63cccc4b5096fd9cbcb08410e69f7932375b4bc6 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 23 Jul 2012 09:44:37 -0700 Subject: Fix type of collision resolution record. Bug: 6759842 Change-Id: I0fe1e6859d8792b959a1306404bd239ab33dd3b4 --- src/com/android/nfc/handover/HandoverManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index 51b123c..f77f780 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -71,6 +71,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, static final byte[] TYPE_BT_OOB = "application/vnd.bluetooth.ep.oob". getBytes(Charset.forName("US_ASCII")); + static final byte[] RTD_COLLISION_RESOLUTION = {0x63, 0x72}; // "cr"; + static final String ACTION_BT_OPP_TRANSFER_PROGRESS = "android.btopp.intent.action.BT_OPP_TRANSFER_PROGRESS"; @@ -642,7 +644,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, static NdefRecord createCollisionRecord() { byte[] random = new byte[2]; new Random().nextBytes(random); - return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_HANDOVER_REQUEST, null, random); + return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, RTD_COLLISION_RESOLUTION, null, random); } NdefRecord createBluetoothAlternateCarrierRecord(boolean activating) { -- cgit v1.1 From 26f6049196acaa9768ba6bdef343216ea878a4c1 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 20 Jul 2012 15:09:37 -0400 Subject: Move NXP JNI and DeviceHost implementation into separate dir. Preparation for the new NCI stack. The idea is to build either the NXP or the NCI stack, triggered by a makefile switch. To that end, move the DeviceHost and JNI implementations in their own directory, so we can build them only if needed. Change-Id: Ibb6aeb11f0bb887e153fd457860b1ad0e39e7933 --- Android.mk | 8 + jni/Android.mk | 35 - jni/com_android_nfc.cpp | 564 ----- jni/com_android_nfc.h | 261 -- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 -- jni/com_android_nfc_NativeLlcpServiceSocket.cpp | 227 -- jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ---- jni/com_android_nfc_NativeNfcManager.cpp | 2623 -------------------- jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ------ jni/com_android_nfc_NativeNfcTag.cpp | 1255 ---------- jni/com_android_nfc_NativeP2pDevice.cpp | 490 ---- jni/com_android_nfc_list.cpp | 210 -- jni/com_android_nfc_list.h | 49 - nxp/jni/Android.mk | 35 + nxp/jni/com_android_nfc.cpp | 564 +++++ nxp/jni/com_android_nfc.h | 261 ++ ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 ++ .../com_android_nfc_NativeLlcpServiceSocket.cpp | 227 ++ nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ++++ nxp/jni/com_android_nfc_NativeNfcManager.cpp | 2623 ++++++++++++++++++++ nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ++++++ nxp/jni/com_android_nfc_NativeNfcTag.cpp | 1255 ++++++++++ nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 490 ++++ nxp/jni/com_android_nfc_list.cpp | 210 ++ nxp/jni/com_android_nfc_list.h | 49 + .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 + .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 + .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 373 +++ .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 + nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 803 ++++++ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 + src/com/android/nfc/NfcService.java | 4 +- .../nfc/nxp/NativeLlcpConnectionlessSocket.java | 78 - .../android/nfc/nxp/NativeLlcpServiceSocket.java | 53 - src/com/android/nfc/nxp/NativeLlcpSocket.java | 99 - src/com/android/nfc/nxp/NativeNfcManager.java | 373 --- .../android/nfc/nxp/NativeNfcSecureElement.java | 67 - src/com/android/nfc/nxp/NativeNfcTag.java | 803 ------ src/com/android/nfc/nxp/NativeP2pDevice.java | 77 - 40 files changed, 8765 insertions(+), 8757 deletions(-) delete mode 100644 jni/Android.mk delete mode 100644 jni/com_android_nfc.cpp delete mode 100644 jni/com_android_nfc.h delete mode 100644 jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpServiceSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpSocket.cpp delete mode 100644 jni/com_android_nfc_NativeNfcManager.cpp delete mode 100755 jni/com_android_nfc_NativeNfcSecureElement.cpp delete mode 100644 jni/com_android_nfc_NativeNfcTag.cpp delete mode 100644 jni/com_android_nfc_NativeP2pDevice.cpp delete mode 100644 jni/com_android_nfc_list.cpp delete mode 100644 jni/com_android_nfc_list.h create mode 100644 nxp/jni/Android.mk create mode 100644 nxp/jni/com_android_nfc.cpp create mode 100644 nxp/jni/com_android_nfc.h create mode 100644 nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcManager.cpp create mode 100755 nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcTag.cpp create mode 100644 nxp/jni/com_android_nfc_NativeP2pDevice.cpp create mode 100644 nxp/jni/com_android_nfc_list.cpp create mode 100644 nxp/jni/com_android_nfc_list.h create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpServiceSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcManager.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcSecureElement.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcTag.java delete mode 100755 src/com/android/nfc/nxp/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index a041854..2cdfc68 100644 --- a/Android.mk +++ b/Android.mk @@ -6,6 +6,14 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) +ifeq ($(NFC_USE_NCI_STACK), true) + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nci) +else + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nxp) +endif + LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform diff --git a/jni/Android.mk b/jni/Android.mk deleted file mode 100644 index 8ae792a..0000000 --- a/jni/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES:= \ - com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ - com_android_nfc_NativeLlcpServiceSocket.cpp \ - com_android_nfc_NativeLlcpSocket.cpp \ - com_android_nfc_NativeNfcManager.cpp \ - com_android_nfc_NativeNfcTag.cpp \ - com_android_nfc_NativeP2pDevice.cpp \ - com_android_nfc_NativeNfcSecureElement.cpp \ - com_android_nfc_list.cpp \ - com_android_nfc.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/libnfc-nxp/src \ - external/libnfc-nxp/inc - -LOCAL_SHARED_LIBRARIES := \ - libnativehelper \ - libcutils \ - libutils \ - libnfc \ - libhardware - -#LOCAL_CFLAGS += -O0 -g - -LOCAL_MODULE := libnfc_jni -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp deleted file mode 100644 index d794d6e..0000000 --- a/jni/com_android_nfc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "errno.h" -#include "com_android_nfc.h" -#include "com_android_nfc_list.h" -#include "phLibNfcStatus.h" - -/* - * JNI Initialization - */ -jint JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - JNIEnv *e; - - ALOGD("NFC Service : loading JNI\n"); - - // Check JNI version - if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) - return JNI_ERR; - - android::vm = jvm; - - if (android::register_com_android_nfc_NativeNfcManager(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcTag(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) - return JNI_ERR; - - return JNI_VERSION_1_6; -} - -namespace android { - -extern struct nfc_jni_native_data *exported_nat; - -JavaVM *vm; - -/* - * JNI Utils - */ -JNIEnv *nfc_get_env() -{ - JNIEnv *e; - if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Current thread is not attached to VM"); - phLibNfc_Mgt_Recovery(); - abort(); - } - return e; -} - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) -{ - /* Create semaphore */ - if(sem_init(&pCallbackData->sem, 0, 0) == -1) - { - ALOGE("Semaphore creation failed (errno=0x%08x)", errno); - return false; - } - - /* Set default status value */ - pCallbackData->status = NFCSTATUS_FAILED; - - /* Copy the context */ - pCallbackData->pContext = pContext; - - /* Add to active semaphore list */ - if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to add the semaphore to the list"); - } - - return true; -} - -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) -{ - /* Destroy semaphore */ - if (sem_destroy(&pCallbackData->sem)) - { - ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); - } - - /* Remove from active semaphore list */ - if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to remove semaphore from the list"); - } - -} - -void nfc_cb_data_releaseAll() -{ - nfc_jni_callback_data* pCallbackData; - - while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) - { - pCallbackData->status = NFCSTATUS_FAILED; - sem_post(&pCallbackData->sem); - } -} - -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj) -{ - jclass cls; - jobject obj; - jmethodID ctor; - - cls = e->FindClass(clsname); - if(cls == NULL) - { - return -1; - ALOGD("Find class error\n"); - } - - - ctor = e->GetMethodID(cls, "", "()V"); - - obj = e->NewObject(cls, ctor); - if(obj == NULL) - { - return -1; - ALOGD("Create object error\n"); - } - - *cached_obj = e->NewGlobalRef(obj); - if(*cached_obj == NULL) - { - e->DeleteLocalRef(obj); - ALOGD("Global ref error\n"); - return -1; - } - - e->DeleteLocalRef(obj); - - return 0; -} - - -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - /* Retrieve native structure address */ - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mNative", "I"); - return (struct nfc_jni_native_data*)e->GetIntField(o, f); -} - -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) -{ - return exported_nat; -} - -static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; - -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) -{ - - pthread_mutexattr_t recursive_attr; - - pthread_mutexattr_init(&recursive_attr); - pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); - - if(nfc_jni_native_monitor == NULL) - { - nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); - } - - if(nfc_jni_native_monitor != NULL) - { - memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); - - if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) - { - ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) - { - ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(!listInit(&nfc_jni_native_monitor->sem_list)) - { - ALOGE("NFC Manager Semaphore List creation failed"); - return NULL; - } - - LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); - - if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) - { - ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) - { - ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); - return NULL; - } - -} - - return nfc_jni_native_monitor; -} - -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) -{ - return nfc_jni_native_monitor; -} - - -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mMode", "S"); - - return e->GetShortField(o, f); -} - - -int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) -{ - - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedTechIndex", "I"); - - return e->GetIntField(o, f); - -} - -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - int connectedTech = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); - - if ((connectedTechIndex != -1) && (techTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(techTypes))) { - jint* technologies = e->GetIntArrayElements(techTypes, 0); - if (technologies != NULL) { - connectedTech = technologies[connectedTechIndex]; - e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); - } - } - - return connectedTech; - -} - -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jint connectedLibNfcType = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); - jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); - - if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { - jint* types = e->GetIntArrayElements(libNfcTypes, 0); - if (types != NULL) { - connectedLibNfcType = types[connectedTechIndex]; - e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); - } - } - return connectedLibNfcType; - -} - -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedHandle", "I"); - - return e->GetIntField(o, f); -} - -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jintArray techtypes; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechList","[I"); - - /* Read the techtypes */ - techtypes = (jintArray) e->GetObjectField(o, f); - - return techtypes; -} - - - -//Display status code -const char* nfc_jni_get_status_name(NFCSTATUS status) -{ - #define STATUS_ENTRY(status) { status, #status } - - struct status_entry { - NFCSTATUS code; - const char *name; - }; - - const struct status_entry sNameTable[] = { - STATUS_ENTRY(NFCSTATUS_SUCCESS), - STATUS_ENTRY(NFCSTATUS_FAILED), - STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), - STATUS_ENTRY(NFCSTATUS_TARGET_LOST), - STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), - STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), - STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_SHUTDOWN), - STATUS_ENTRY(NFCSTATUS_ABORTED), - STATUS_ENTRY(NFCSTATUS_REJECTED ), - STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), - STATUS_ENTRY(NFCSTATUS_PENDING), - STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), - STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), - STATUS_ENTRY(NFCSTATUS_BUSY), - STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), - STATUS_ENTRY(NFCSTATUS_DESELECTED), - STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), - STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), - STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), - STATUS_ENTRY(NFCSTATUS_RF_ERROR), - STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), - STATUS_ENTRY(NFCSTATUS_INVALID_STATE), - STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), - STATUS_ENTRY(NFCSTATUS_RELEASED), - STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), - STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), - STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_READ_FAILED), - STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), - STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), - STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), - STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), - STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), - STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), - }; - - int i = sizeof(sNameTable)/sizeof(status_entry); - - while(i>0) - { - i--; - if (sNameTable[i].code == PHNFCSTATUS(status)) - { - return sNameTable[i].name; - } - } - - return "UNKNOWN"; -} - -int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, - int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { - bool found = false; - for (int i = 0; i < listSize; i++) { - if (techList[i] == techToAdd) { - found = true; - break; - } - } - if (!found && listSize < maxListSize) { - techList[listSize] = techToAdd; - handleList[listSize] = handleToAdd; - typeList[listSize] = typeToAdd; - return listSize + 1; - } - else { - return listSize; - } -} - - -#define MAX_NUM_TECHNOLOGIES 32 - -/* - * Utility to get a technology tree and a corresponding handle list from a detected tag. - */ -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* libnfcTypeList) -{ - int technologies[MAX_NUM_TECHNOLOGIES]; - int handles[MAX_NUM_TECHNOLOGIES]; - int libnfctypes[MAX_NUM_TECHNOLOGIES]; - - int index = 0; - // TODO: This counts from up to down because on multi-protocols, the - // ISO handle is usually the second, and we prefer the ISO. Should implement - // a method to find the "preferred handle order" and use that instead, - // since we shouldn't have dependencies on the tech list ordering. - for (int target = count - 1; target >= 0; target--) { - int type = devList[target].psRemoteDevInfo->RemDevType; - int handle = devList[target].hTargetDev; - switch (type) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - break; - } - case phNfc_eISO14443_4B_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO14443_3A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - case phNfc_eISO14443_B_PICC: - { - // TODO a bug in libnfc will cause 14443-3B only cards - // to be returned as this type as well, but these cards - // are very rare. Hence assume it's -4B - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO15693_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); - }break; - case phNfc_eMifare_PICC: - { - // We don't want to be too clever here; libnfc has already determined - // it's a Mifare, so we only check for UL, for all other tags - // we assume it's a mifare classic. This should make us more - // future-proof. - int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; - switch(sak) - { - case 0x00: - // could be UL or UL-C - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); - break; - default: - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); - break; - } - }break; - case phNfc_eFelica_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); - }break; - case phNfc_eJewel_PICC: - { - // Jewel represented as NfcA - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - default: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); - } - } - } - - // Build the Java arrays - if (techList != NULL) { - *techList = e->NewIntArray(index); - e->SetIntArrayRegion(*techList, 0, index, technologies); - } - - if (handleList != NULL) { - *handleList = e->NewIntArray(index); - e->SetIntArrayRegion(*handleList, 0, index, handles); - } - - if (libnfcTypeList != NULL) { - *libnfcTypeList = e->NewIntArray(index); - e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); - } -} - -} // namespace android diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h deleted file mode 100644 index b876dad..0000000 --- a/jni/com_android_nfc.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_JNI_H__ -#define __COM_ANDROID_NFC_JNI_H__ - -#define LOG_TAG "NFCJNI" - -#include -#include - -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include - -} -#include // for property_get - - -/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ -#define DISCOVERY_MODE_TAG_READER 0 -#define DISCOVERY_MODE_NFCIP1 1 -#define DISCOVERY_MODE_CARD_EMULATION 2 - -#define DISCOVERY_MODE_TABLE_SIZE 3 - -#define DISCOVERY_MODE_DISABLED 0 -#define DISCOVERY_MODE_ENABLED 1 - -#define MODE_P2P_TARGET 0 -#define MODE_P2P_INITIATOR 1 - -/* Properties values */ -#define PROPERTY_LLCP_LTO 0 -#define PROPERTY_LLCP_MIU 1 -#define PROPERTY_LLCP_WKS 2 -#define PROPERTY_LLCP_OPT 3 -#define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 -#define PROPERTY_NFC_DISCOVERY_F 6 -#define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 - -/* Error codes */ -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -/* Pre-defined card read/write state values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_UNKNOWN_TYPE -1 -#define NDEF_TYPE1_TAG 1 -#define NDEF_TYPE2_TAG 2 -#define NDEF_TYPE3_TAG 3 -#define NDEF_TYPE4_TAG 4 -#define NDEF_MIFARE_CLASSIC_TAG 101 -#define NDEF_ICODE_SLI_TAG 102 - -/* Pre-defined tag type values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_MODE_READ_ONLY 1 -#define NDEF_MODE_READ_WRITE 2 -#define NDEF_MODE_UNKNOWN 3 - - -/* Name strings for target types. These *must* match the values in TagTechnology.java */ -#define TARGET_TYPE_UNKNOWN -1 -#define TARGET_TYPE_ISO14443_3A 1 -#define TARGET_TYPE_ISO14443_3B 2 -#define TARGET_TYPE_ISO14443_4 3 -#define TARGET_TYPE_FELICA 4 -#define TARGET_TYPE_ISO15693 5 -#define TARGET_TYPE_NDEF 6 -#define TARGET_TYPE_NDEF_FORMATABLE 7 -#define TARGET_TYPE_MIFARE_CLASSIC 8 -#define TARGET_TYPE_MIFARE_UL 9 - -#define SMX_SECURE_ELEMENT_ID 11259375 - -/* Maximum byte length of an AID. */ -#define AID_MAXLEN 16 - -/* Utility macros for logging */ -#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN - -#if 0 - #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); - #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) - #define TRACE_ENABLED 1 -#else - #define LOG_CALLBACK(...) - #define TRACE(...) - #define TRACE_ENABLED 0 -#endif - -struct nfc_jni_native_data -{ - /* Thread handle */ - pthread_t thread; - int running; - - /* Our VM */ - JavaVM *vm; - int env_version; - - /* Reference to the NFCManager instance */ - jobject manager; - - /* Cached objects */ - jobject cached_NfcTag; - jobject cached_P2pDevice; - - /* Target discovery configuration */ - int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - - /* Secure Element selected */ - int seId; - - /* LLCP params */ - int lto; - int miu; - int wks; - int opt; - - /* Tag detected */ - jobject tag; - - /* Lib Status */ - NFCSTATUS status; - - /* p2p modes */ - int p2p_initiator_modes; - int p2p_target_modes; - -}; - -typedef struct nfc_jni_native_monitor -{ - /* Mutex protecting native library against reentrance */ - pthread_mutex_t reentrance_mutex; - - /* Mutex protecting native library against concurrency */ - pthread_mutex_t concurrency_mutex; - - /* List used to track pending semaphores waiting for callback */ - struct listHead sem_list; - - /* List used to track incoming socket requests (and associated sync variables) */ - LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; - pthread_mutex_t incoming_socket_mutex; - pthread_cond_t incoming_socket_cond; - -} nfc_jni_native_monitor_t; - -typedef struct nfc_jni_callback_data -{ - /* Semaphore used to wait for callback */ - sem_t sem; - - /* Used to store the status sent by the callback */ - NFCSTATUS status; - - /* Used to provide a local context to the callback */ - void* pContext; - -} nfc_jni_callback_data_t; - -typedef struct nfc_jni_listen_data -{ - /* LLCP server socket receiving the connection request */ - phLibNfc_Handle pServerSocket; - - /* LLCP socket created from the connection request */ - phLibNfc_Handle pIncomingSocket; - - /* List entries */ - LIST_ENTRY(nfc_jni_listen_data) entries; - -} nfc_jni_listen_data_t; - -/* TODO: treat errors and add traces */ -#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) -#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) -#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) -#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) - -namespace android { - -extern JavaVM *vm; - -JNIEnv *nfc_get_env(); - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); -void nfc_cb_data_releaseAll(); - -const char* nfc_jni_get_status_name(NFCSTATUS status); -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj); -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); - -int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* typeList); - -/* P2P */ -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); - -/* TAG */ -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); - -/* LLCP */ -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e); -int register_com_android_nfc_NativeNfcTag(JNIEnv *e); -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); - -} // namespace android - -#endif diff --git a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp deleted file mode 100644 index 188edb4..0000000 --- a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - pCallbackData->pContext = (void*)ssap; - TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_sendTo_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* -* Methods -*/ -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_SendTo()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SendTo(hRemoteDevice, - hLlcpSocket, - nsap, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) -{ - NFCSTATUS ret; - struct timespec ts; - uint8_t ssap; - jobject llcpPacket = NULL; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer; - jclass clsLlcpPacket; - jfieldID f; - jbyteArray receivedData = NULL; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create new LlcpPacket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) - { - ALOGE("Find LlcpPacket class error"); - goto clean_and_return; - } - - /* Get NativeConnectionless class object */ - clsLlcpPacket = e->GetObjectClass(llcpPacket); - if(e->ExceptionCheck()) - { - ALOGE("Get Object class error"); - goto clean_and_return; - } - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); - - sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); - sReceiveBuffer.length = linkMiu; - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - &cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ssap = (uint32_t)cb_data.pContext; - TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); - - /* Set Llcp Packet remote SAP */ - f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); - e->SetIntField(llcpPacket, f,(jbyte)ssap); - - /* Set Llcp Packet Buffer */ - ALOGD("Set LlcpPacket Data Buffer\n"); - f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); - receivedData = e->NewByteArray(sReceiveBuffer.length); - e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); - e->SetObjectField(llcpPacket, f, receivedData); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return llcpPacket; -} - -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - TRACE("Close Connectionless socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, - - {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, - - {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", - gMethods, NELEM(gMethods)); -} - -} // android namespace diff --git a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp deleted file mode 100644 index 92de3e4..0000000 --- a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode); -/* - * Callbacks - */ -static void nfc_jni_llcp_accept_socket_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -/* - * Utils - */ - -static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, - phLibNfc_Handle hServerSocket) -{ - nfc_jni_listen_data_t * pListenData; - phLibNfc_Handle pIncomingSocket = NULL; - - /* Look for a pending incoming connection on the current server */ - LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) - { - if (pListenData->pServerSocket == hServerSocket) - { - pIncomingSocket = pListenData->pIncomingSocket; - LIST_REMOVE(pListenData, entries); - free(pListenData); - break; - } - } - - return pIncomingSocket; -} - -/* - * Methods - */ -static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret = NFCSTATUS_SUCCESS; - struct timespec ts; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - jfieldID f; - jclass clsNativeLlcpSocket; - jobject clientSocket = NULL; - struct nfc_jni_callback_data cb_data; - phLibNfc_Handle hIncomingSocket, hServerSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Get server socket */ - hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Set socket options with the socket options of the service */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - - while(cb_data.status != NFCSTATUS_SUCCESS) - { - /* Wait for tag Notification */ - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { - pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); - } - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - /* Accept the incomming socket */ - TRACE("phLibNfc_Llcp_Accept()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Accept( hIncomingSocket, - &sOptions, - &sWorkingBuffer, - nfc_jni_llcp_transport_socket_err_callback, - nfc_jni_llcp_accept_socket_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - // NOTE: This may happen if link went down since incoming socket detected, then - // just drop it and start a new accept loop. - ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - continue; - } - TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ - ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); - } - } - - /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGD("LLCP Socket creation error"); - goto clean_and_return; - } - - /* Get NativeConnectionOriented class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGD("LLCP Socket get class object error"); - goto clean_and_return; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hIncomingSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - - TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return clientSocket; -} - -static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - TRACE("Close Service socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - /* TODO: implement accept abort */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("Close Service socket OK"); - return TRUE; - } - else - { - ALOGD("Close Service socket KO"); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_NativeLlcpServiceSocket_doAccept}, - - {"doClose", "()Z", - (void *)com_NativeLlcpServiceSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeLlcpSocket.cpp b/jni/com_android_nfc_NativeLlcpSocket.cpp deleted file mode 100644 index 0c0b830..0000000 --- a/jni/com_android_nfc_NativeLlcpSocket.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_disconnect_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - TRACE("Socket connected\n"); - } - else - { - ALOGD("Socket not connected:"); - switch(nErrCode) - { - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: - { - ALOGD("> SAP NOT ACTIVE\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: - { - ALOGD("> SAP NOT FOUND\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: - { - ALOGD("> CONNECT REJECTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: - { - ALOGD("> CONNECT NOT ACCEPTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: - { - ALOGD("> SOCKET NOT AVAILABLE\n"); - }break; - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - - - -static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Methods - */ -static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_Llcp_Connect(%d)",nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Connect(hRemoteDevice, - hLlcpSocket, - nSap, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("LLCP Connect request failed"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) -{ - NFCSTATUS ret; - struct timespec ts; - phNfc_sData_t serviceName = {0}; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Service socket */ - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - - TRACE("phLibNfc_Llcp_ConnectByUri()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, - hLlcpSocket, - &serviceName, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_Send()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Send(hRemoteDevice, - hLlcpSocket, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jint result = -1; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); - sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); - - TRACE("phLibNfc_Llcp_Recv()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Recv(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_PENDING) - { - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - } - else if (ret == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - else - { - /* Return status should be either SUCCESS or PENDING */ - ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - -clean_and_return: - if (sReceiveBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.miu; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.rw; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnect}, - - {"doConnectBy", "(Ljava/lang/String;)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, - - {"doClose", "()Z", - (void *)com_android_nfc_NativeLlcpSocket_doClose}, - - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeLlcpSocket_doSend}, - - {"doReceive", "([B)I", - (void *)com_android_nfc_NativeLlcpSocket_doReceive}, - - {"doGetRemoteSocketMiu", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, - - {"doGetRemoteSocketRw", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, -}; - - -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp deleted file mode 100644 index e6da0fa..0000000 --- a/jni/com_android_nfc_NativeNfcManager.cpp +++ /dev/null @@ -1,2623 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "com_android_nfc.h" - -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -extern uint32_t libnfc_llc_error_count; - -static phLibNfc_sConfig_t gDrvCfg; -void *gHWRef; -static phNfc_sData_t gInputParam; -static phNfc_sData_t gOutputParam; - -uint8_t device_connected_flag; -static bool driverConfigured = FALSE; - -static phLibNfc_Handle hLlcpHandle; -static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; -static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; - -static jmethodID cached_NfcManager_notifyNdefMessageListeners; -static jmethodID cached_NfcManager_notifyTransactionListeners; -static jmethodID cached_NfcManager_notifyLlcpLinkActivation; -static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; -static jmethodID cached_NfcManager_notifyTargetDeselected; - -static jmethodID cached_NfcManager_notifySeFieldActivated; -static jmethodID cached_NfcManager_notifySeFieldDeactivated; - -static jmethodID cached_NfcManager_notifySeApduReceived; -static jmethodID cached_NfcManager_notifySeMifareAccess; -static jmethodID cached_NfcManager_notifySeEmvCardRemoval; - -namespace android { - -phLibNfc_Handle storedHandle = 0; - -struct nfc_jni_native_data *exported_nat = NULL; - -/* Internal functions declaration */ -static void *nfc_jni_client_thread(void *arg); -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_se_set_mode_callback(void *context, - phLibNfc_Handle handle, NFCSTATUS status); -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status); -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); -static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); - -/* - * Deferred callback called when client thread must be exited - */ -static void client_kill_deferred_call(void* arg) -{ - struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; - - nat->running = FALSE; -} - -static void kill_client(nfc_jni_native_data *nat) -{ - phDal4Nfc_Message_Wrapper_t wrapper; - phLibNfc_DeferredCall_t *pMsg; - - usleep(50000); - - ALOGD("Terminating client thread..."); - - pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); - pMsg->pCallback = client_kill_deferred_call; - pMsg->pParameter = (void*)nat; - - wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; - wrapper.msg.pMsgData = pMsg; - wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); - - phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); -} - -static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_ioctl_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_deinit_download_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) -{ - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - struct timespec ts; - NFCSTATUS status = NFCSTATUS_FAILED; - phLibNfc_StackCapabilities_t caps; - struct nfc_jni_callback_data cb_data; - bool result; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - if(update) - { - //deinit - TRACE("phLibNfc_Mgt_DeInitialize() (download)"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts)) - { - ALOGW("Deinitialization timed out (download)"); - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("Deinitialization FAILED (download)"); - } - TRACE("Deinitialization SUCCESS (download)"); - } - - result = performDownload(nat, false); - - if (!result) { - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - status = cb_data.status; - goto clean_and_return; - } - - /* ====== CAPABILITIES ======= */ - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /*Download is successful*/ - status = NFCSTATUS_SUCCESS; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return status; -} - -static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) -{ - char value[PROPERTY_VALUE_MAX]; - int result = FALSE; - NFCSTATUS status; - - /* ====== CONFIGURE DRIVER ======= */ - /* Configure hardware link */ - gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); - - TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); - REENTRANCE_UNLOCK(); - if(status == NFCSTATUS_ALREADY_INITIALISED) { - ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) - { - ALOGE("pthread_create failed"); - goto clean_and_return; - } - - driverConfigured = TRUE; - -clean_and_return: - return result; -} - -static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) -{ - int result = FALSE; - NFCSTATUS status; - - /* Unconfigure driver */ - TRACE("phLibNfc_Mgt_UnConfigureDriver()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); - } - else - { - ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = TRUE; - } - - driverConfigured = FALSE; - - return result; -} - -/* Initialization function */ -static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { - struct timespec ts; - uint8_t resp[16]; - NFCSTATUS status; - phLibNfc_StackCapabilities_t caps; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; - phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; - struct nfc_jni_callback_data cb_data; - uint8_t firmware_status; - uint8_t update = TRUE; - int result = JNI_FALSE; - const hw_module_t* hw_module; - nfc_pn544_device_t* pn544_dev = NULL; - int ret = 0; - ALOGD("Start Initialization\n"); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Get EEPROM values and device port from product-specific settings */ - ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); - if (ret) { - ALOGE("hw_get_module() failed."); - goto clean_and_return; - } - ret = nfc_pn544_open(hw_module, &pn544_dev); - if (ret) { - ALOGE("Could not open pn544 hw_module."); - goto clean_and_return; - } - if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { - ALOGE("Could not load EEPROM settings"); - goto clean_and_return; - } - - /* Reset device connected handle */ - device_connected_flag = 0; - - /* Reset stored handle */ - storedHandle = 0; - - /* Initialize Driver */ - if(!driverConfigured) - { - nfc_jni_configure_driver(nat); - } - - /* ====== INITIALIZE ======= */ - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - update = FALSE; - goto force_download; - } - TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - update = FALSE; - goto force_download; - } - - /* ====== CAPABILITIES ======= */ - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /* ====== FIRMWARE VERSION ======= */ - if(caps.psDevCapabilities.firmware_update_info) - { -force_download: - for (i=0; i<3; i++) - { - TRACE("Firmware version not UpToDate"); - status = nfc_jni_download_locked(nat, update); - if(status == NFCSTATUS_SUCCESS) - { - ALOGI("Firmware update SUCCESS"); - break; - } - ALOGW("Firmware update FAILED"); - update = FALSE; - } - if(i>=3) - { - ALOGE("Unable to update firmware, giving up"); - goto clean_and_return; - } - } - else - { - TRACE("Firmware version UpToDate"); - } - /* ====== EEPROM SETTINGS ======= */ - - // Update EEPROM settings - TRACE("****** START EEPROM SETTINGS UPDATE ******"); - for (i = 0; i < pn544_dev->num_eeprom_settings; i++) - { - char eeprom_property[PROPERTY_KEY_MAX]; - char eeprom_value[PROPERTY_VALUE_MAX]; - uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); - TRACE("> EEPROM SETTING: %d", i); - - // Check for override of this EEPROM value in properties - snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", - eeprom_base[1], eeprom_base[2]); - TRACE(">> Checking property: %s", eeprom_property); - if (property_get(eeprom_property, eeprom_value, "") == 2) { - int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); - ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", - eeprom_base[1], eeprom_base[2], eeprom_value_num); - eeprom_base[3] = eeprom_value_num; - } - - TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], - eeprom_base[3]); - gInputParam.buffer = eeprom_base; - gInputParam.length = 0x04; - gOutputParam.buffer = resp; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if (cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - } - TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); - - /* ====== SECURE ELEMENTS ======= */ - - REENTRANCE_LOCK(); - ALOGD("phLibNfc_SE_GetSecureElementList()"); - status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - - ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i < No_SE; i++) - { - if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); - } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); - } - - /* Set SE mode - Off */ - REENTRANCE_LOCK(); - status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, - phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - } - - /* ====== LLCP ======= */ - - /* LLCP Params */ - TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); - LlcpConfigInfo.miu = nat->miu; - LlcpConfigInfo.lto = nat->lto; - LlcpConfigInfo.wks = nat->wks; - LlcpConfigInfo.option = nat->opt; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, - nfc_jni_llcpcfg_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* ===== DISCOVERY ==== */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.Duration = 300000; /* in ms */ - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Register for the card emulation mode */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); - - - /* ====== END ======= */ - - ALOGI("NFC Initialized"); - - result = TRUE; - -clean_and_return: - if (result != TRUE) - { - if(nat) - { - kill_client(nat); - } - } - if (pn544_dev != NULL) { - nfc_pn544_close(pn544_dev); - } - nfc_cb_data_deinit(&cb_data); - - return result; -} - -static int is_user_build() { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.type", value, ""); - return !strncmp("user", value, PROPERTY_VALUE_MAX); -} - -/* - * Last-chance fallback when there is no clean way to recover - * Performs a software reset - */ -void emergency_recovery(struct nfc_jni_native_data *nat) { - if (!is_user_build()) { - ALOGE("emergency_recovery: force restart of NFC service"); - } else { - // dont recover immediately, so we can debug - unsigned int t; - for (t=1; t < 1000000; t <<= 1) { - ALOGE("emergency_recovery: NFC stack dead-locked"); - sleep(t); - } - } - phLibNfc_Mgt_Recovery(); - abort(); // force a noisy crash -} - -void nfc_jni_reset_timeout_values() -{ - REENTRANCE_LOCK(); - phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); - phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); - phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); - phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); - REENTRANCE_UNLOCK(); -} - -/* - * Restart the polling loop when unable to perform disconnect - */ -void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) -{ - nfc_jni_start_discovery_locked(nat, true); -} - - /* - * Utility to recover UID from target infos - */ -static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - phNfc_sData_t uid; - - switch(psRemoteDevInfo->RemDevType) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_3A_PICC: - case phNfc_eMifare_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; - break; - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; - uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); - break; - case phNfc_eFelica_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; - uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; - break; - case phNfc_eJewel_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; - break; - case phNfc_eISO15693_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; - break; - case phNfc_eNfcIP1_Target: - case phNfc_eNfcIP1_Initiator: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; - uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; - break; - default: - uid.buffer = NULL; - uid.length = 0; - break; - } - - return uid; -} - -/* - * NFC stack message processing - */ -static void *nfc_jni_client_thread(void *arg) -{ - struct nfc_jni_native_data *nat; - JNIEnv *e; - JavaVMAttachArgs thread_args; - phDal4Nfc_Message_Wrapper_t wrapper; - - nat = (struct nfc_jni_native_data *)arg; - - thread_args.name = "NFC Message Loop"; - thread_args.version = nat->env_version; - thread_args.group = NULL; - - nat->vm->AttachCurrentThread(&e, &thread_args); - pthread_setname_np(pthread_self(), "message"); - - TRACE("NFC client started"); - nat->running = TRUE; - while(nat->running == TRUE) - { - /* Fetch next message from the NFC stack message queue */ - if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, - sizeof(phLibNfc_Message_t), 0, 0) == -1) - { - ALOGE("NFC client received bad message"); - continue; - } - - switch(wrapper.msg.eMsgType) - { - case PH_LIBNFC_DEFERREDCALL_MSG: - { - phLibNfc_DeferredCall_t *msg = - (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); - - REENTRANCE_LOCK(); - msg->pCallback(msg->pParameter); - REENTRANCE_UNLOCK(); - - break; - } - } - } - TRACE("NFC client stopped"); - - nat->vm->DetachCurrentThread(); - - return NULL; -} - -extern uint8_t nfc_jni_is_ndef; -extern uint8_t *nfc_jni_ndef_buf; -extern uint32_t nfc_jni_ndef_buf_len; - -static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = -{ - 3, - { 0x46, 0x66, 0x6D } -}; - -/* - * Callbacks - */ - -/* P2P - LLCP callbacks */ -static void nfc_jni_llcp_linkStatus_callback(void *pContext, - phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) -{ - phFriNfc_Llcp_sLinkParameters_t sLinkParams; - JNIEnv *e; - NFCSTATUS status; - - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; - - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - /* Update link status */ - g_eLinkStatus = eLinkStatus; - - if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) - { - REENTRANCE_LOCK(); - status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGW("GetRemote Info failded - Status = %02x",status); - } - else - { - ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, - sLinkParams.miu, - sLinkParams.option, - sLinkParams.wks); - device_connected_flag = 1; - } - } - else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) - { - ALOGI("LLCP Link deactivated"); - free(pContextData); - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Reset incoming socket list */ - while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) - { - pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); - LIST_REMOVE(pListenData, entries); - free(pListenData); - } - - /* Notify manager that the LLCP is lost or deactivated */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } -} - -static void nfc_jni_checkLlcp_callback(void *context, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; - - LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, - phLibNfc_Handle hIncomingSocket) -{ - phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - - /* Store the connection request */ - pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); - if (pListenData == NULL) - { - ALOGE("Failed to create structure to handle incoming LLCP connection request"); - goto clean_and_return; - } - pListenData->pServerSocket = hServiceSocket; - pListenData->pIncomingSocket = hIncomingSocket; - LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); - - /* Signal pending accept operations that the list is updated */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - -clean_and_return: - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); -} - -void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode) -{ - PHNFC_UNUSED_VARIABLE(pContext); - - TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); - - if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) - { - ALOGW("Frame Rejected - Disconnected"); - } - else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) - { - ALOGD("Socket Disconnected"); - } -} - - -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_discover_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNoOfRemoteDev) -{ - // Always prefer p2p targets over other targets. Otherwise, select the first target - // reported. - uint8_t preferred_index = 0; - for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { - if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { - preferred_index = i; - } - } - return preferred_index; -} - -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status) -{ - JNIEnv *e; - NFCSTATUS ret; - jclass tag_cls = NULL; - jobject target_array; - jobject tag; - jmethodID ctor; - jfieldID f; - const char * typeName; - jbyteArray tagUid; - jbyteArray generalBytes = NULL; - struct nfc_jni_native_data *nat; - struct timespec ts; - phNfc_sData_t data; - int i; - int target_index = 0; // Target that will be reported (if multiple can be >0) - - nat = (struct nfc_jni_native_data *)pContext; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); - - /* Notify manager that a target was deselected */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); - TRACE("Discovered %d tags", uNofRemoteDev); - - target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); - - /* Reset device connected flag */ - device_connected_flag = 1; - phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; - phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - - tag_cls = e->GetObjectClass(nat->cached_P2pDevice); - if(e->ExceptionCheck()) - { - ALOGE("Get Object Class Error"); - kill_client(nat); - return; - } - - /* New target instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - /* Set P2P Target mode */ - f = e->GetFieldID(tag_cls, "mMode", "I"); - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - ALOGD("Discovered P2P Initiator"); - e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); - } - else - { - ALOGD("Discovered P2P Target"); - e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); - } - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - /* Set General Bytes */ - f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes length ="); - for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) - { - ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); - } - - generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - - e->SetByteArrayRegion(generalBytes, 0, - remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, - (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); - - e->SetObjectField(tag, f, generalBytes); - } - - /* Set tag handle */ - f = e->GetFieldID(tag_cls, "mHandle", "I"); - e->SetIntField(tag, f,(jint)remDevHandle); - TRACE("Target handle = 0x%08x",remDevHandle); - } - else - { - tag_cls = e->GetObjectClass(nat->cached_NfcTag); - if(e->ExceptionCheck()) - { - kill_client(nat); - return; - } - - /* New tag instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - bool multi_protocol = false; - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - TRACE("Multiple Protocol TAG detected\n"); - multi_protocol = true; - } - - /* Set tag UID */ - f = e->GetFieldID(tag_cls, "mUid", "[B"); - data = get_target_uid(remDevInfo); - tagUid = e->NewByteArray(data.length); - if(data.length > 0) - { - e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); - } - e->SetObjectField(tag, f, tagUid); - - /* Generate technology list */ - jintArray techList; - jintArray handleList; - jintArray typeList; - nfc_jni_get_technology_tree(e, psRemoteDevList, - multi_protocol ? uNofRemoteDev : 1, - &techList, &handleList, &typeList); - - /* Push the technology list into the java object */ - f = e->GetFieldID(tag_cls, "mTechList", "[I"); - e->SetObjectField(tag, f, techList); - - f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); - e->SetObjectField(tag, f, handleList); - - f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); - e->SetObjectField(tag, f, typeList); - - f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); - e->SetIntField(tag, f,(jint)-1); - - f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); - e->SetIntField(tag, f,(jint)-1); - } - - storedHandle = remDevHandle; - if (nat->tag != NULL) { - e->DeleteGlobalRef(nat->tag); - } - nat->tag = e->NewGlobalRef(tag); - - /* Notify the service */ - TRACE("Notify Nfc Service"); - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - /* Store the hanlde of the P2P device */ - hLlcpHandle = remDevHandle; - - /* Notify manager that new a P2P device was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - /* Notify manager that new a tag was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - e->DeleteLocalRef(tag); - } -} - -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_init_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_deinit_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Card Emulation callback */ -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) -{ - JNIEnv *e; - jobject tmp_array = NULL; - jobject mifare_block = NULL; - struct nfc_jni_native_data *nat; - phNfc_sData_t *aid; - phNfc_sData_t *mifare_command; - struct nfc_jni_callback_data *pCallbackData; - int i=0; - - LOG_CALLBACK("nfc_jni_transaction_callback", status); - - nat = (struct nfc_jni_native_data *)context; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_SUCCESS) - { - switch(evt_type) - { - case phLibNfc_eSE_EvtStartTransaction: - { - TRACE("> SE EVT_START_TRANSACTION"); - if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) - { - aid = &(evt_info->UiccEvtInfo.aid); - - ALOGD("> AID DETECTED"); - - if(aid != NULL) - { - if (TRACE_ENABLED == 1) { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); - } - ALOGD("> AID: %s", aid_str); - } - tmp_array = e->NewByteArray(aid->length); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - goto error; - } - - TRACE("Notify Nfc Service"); - /* Notify manager that a new event occurred on a SE */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - ALOGD("> NO AID DETECTED"); - } - }break; - - case phLibNfc_eSE_EvtApduReceived: - { - phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); - TRACE("> SE EVT_APDU_RECEIVED"); - - if (apdu != NULL) { - TRACE(" APDU length=%d", apdu->length); - tmp_array = e->NewByteArray(apdu->length); - if (tmp_array == NULL) { - goto error; - } - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); - if (e->ExceptionCheck()) { - goto error; - } - } else { - TRACE(" APDU EMPTY"); - } - - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); - }break; - - case phLibNfc_eSE_EvtCardRemoval: - { - TRACE("> SE EVT_EMV_CARD_REMOVAL"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); - }break; - - case phLibNfc_eSE_EvtMifareAccess: - { - TRACE("> SE EVT_MIFARE_ACCESS"); - mifare_command = &(evt_info->UiccEvtInfo.aid); - TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); - tmp_array = e->NewByteArray(2); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); - }break; - - case phLibNfc_eSE_EvtFieldOn: - { - TRACE("> SE EVT_FIELD_ON"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); - }break; - - case phLibNfc_eSE_EvtFieldOff: - { - TRACE("> SE EVT_FIELD_OFF"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); - }break; - - default: - { - TRACE("Unknown SE event"); - }break; - } - } - else - { - ALOGE("SE transaction notification error"); - goto error; - } - - /* Function finished, now clean and return */ - goto clean_and_return; - - error: - /* In case of error, just discard the notification */ - ALOGE("Failed to send SE transaction notification"); - e->ExceptionClear(); - - clean_and_return: - if(tmp_array != NULL) - { - e->DeleteLocalRef(tmp_array); - } -} - -static void nfc_jni_se_set_mode_callback(void *pContext, - phLibNfc_Handle handle, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* - * NFCManager methods - */ - -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) -{ - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ - nfc_jni_reset_timeout_values(); - - /* Reload the p2p modes */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Start Polling loop */ - TRACE("****** Start NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, - nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - -static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) -{ - phLibNfc_sADD_Cfg_t discovery_cfg; - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - discovery_cfg.PollDevInfo.PollEnabled = 0; - discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; - discovery_cfg.NfcIP_Target_Mode = 0; - discovery_cfg.NfcIP_Tgt_Disable = TRUE; - - /* Start Polling loop */ - TRACE("****** Stop NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - - -static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nfc_jni_stop_discovery_locked(nat); - - CONCURRENCY_UNLOCK(); - -} - -static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - nat = nfc_jni_get_nat(e, o); - - /* Register callback for remote device notifications. - * Must re-register every time we turn on discovery, since other operations - * (such as opening the Secure Element) can change the remote device - * notification callback*/ - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", - nat->registry_info.Jewel==TRUE?"J":"", - nat->registry_info.MifareUL==TRUE?"UL":"", - nat->registry_info.MifareStd==TRUE?"Mi":"", - nat->registry_info.Felica==TRUE?"F":"", - nat->registry_info.ISO14443_4A==TRUE?"4A":"", - nat->registry_info.ISO14443_4B==TRUE?"4B":"", - nat->registry_info.NFC==TRUE?"P2P":"", - nat->registry_info.ISO15693==TRUE?"R":"", ret); - - nfc_jni_start_discovery_locked(nat, false); -clean_and_return: - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { - CONCURRENCY_LOCK(); - nfc_jni_reset_timeout_values(); - CONCURRENCY_UNLOCK(); -} - -static void setFelicaTimeout(jint timeout) { - // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. - // It can be set to 0 to disable the timeout altogether, in which case we - // use the sw watchdog as a fallback. - if (timeout <= 255) { - phLibNfc_SetFelicaTimeout(timeout); - } else { - // Disable hw timeout, use sw watchdog for timeout - phLibNfc_SetFelicaTimeout(0); - phLibNfc_SetHciTimeout(timeout); - } - -} -// Calculates ceiling log2 of value -static unsigned int log2(int value) { - unsigned int ret = 0; - bool isPowerOf2 = ((value & (value - 1)) == 0); - while ( (value >> ret) > 1 ) ret++; - if (!isPowerOf2) ret++; - return ret; -} - -// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X -// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X -// -// We keep the constant part of the formula in a static; note the factor -// 1000 off, which is due to the fact that the formula calculates seconds, -// but this method gets milliseconds as an argument. -static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; - -static int calcTimeout(int timeout_in_ms) { - // timeout = (256 * 16 / 13560000) * 2 ^ X - // First find the first X for which timeout > requested timeout - return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); -} - -static void setIsoDepTimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - // Then re-compute the actual timeout based on X - double actual_timeout = nxp_nfc_timeout_factor * (1 << value); - // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, - // but it will take some time to get back through the sw layers. - // 500 ms should be enough). - phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); - value |= 0x10; // bit 4 to enable timeout - phLibNfc_SetIsoXchgTimeout(value); - } - else { - // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout - // must be disabled completely, to prevent the PN544 from aborting - // the transaction. We reuse the HCI sw watchdog to catch the timeout - // in that case. - phLibNfc_SetIsoXchgTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static void setNfcATimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - phLibNfc_SetMifareRawTimeout(value); - } - else { - // Disable mifare raw timeout, use HCI sw watchdog instead - phLibNfc_SetMifareRawTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, - jint tech, jint timeout) { - bool success = false; - CONCURRENCY_LOCK(); - if (timeout <= 0) { - ALOGE("Timeout must be positive."); - return false; - } else { - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - setNfcATimeout(timeout); - success = true; - break; - case TARGET_TYPE_ISO14443_4: - setIsoDepTimeout(timeout); - success = true; - break; - case TARGET_TYPE_FELICA: - setFelicaTimeout(timeout); - success = true; - break; - default: - ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); - success = false; - } - } - CONCURRENCY_UNLOCK(); - return success; -} - -static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, - jint tech) { - int timeout = -1; - CONCURRENCY_LOCK(); - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - timeout = phLibNfc_GetMifareRawTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_ISO14443_4: - timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_FELICA: - timeout = phLibNfc_GetFelicaTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Felica timeout already in ms - } - break; - default: - ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); - break; - } - CONCURRENCY_UNLOCK(); - return timeout; -} - - -static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct nfc_jni_native_data *nat = NULL; - jclass cls; - jobject obj; - jfieldID f; - - TRACE("****** Init Native Structure ******"); - - /* Initialize native structure */ - nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); - if(nat == NULL) - { - ALOGD("malloc of nfc_jni_native_data failed"); - return FALSE; - } - memset(nat, 0, sizeof(*nat)); - e->GetJavaVM(&(nat->vm)); - nat->env_version = e->GetVersion(); - nat->manager = e->NewGlobalRef(o); - - cls = e->GetObjectClass(o); - f = e->GetFieldID(cls, "mNative", "I"); - e->SetIntField(o, f, (jint)nat); - - /* Initialize native cached references */ - cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); - - cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, - "notifyTransactionListeners", "([B)V"); - - cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, - "notifyTargetDeselected","()V"); - - cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, - "notifySeFieldActivated", "()V"); - - cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, - "notifySeFieldDeactivated", "()V"); - - cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, - "notifySeApduReceived", "([B)V"); - - cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, - "notifySeMifareAccess", "([B)V"); - - cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, - "notifySeEmvCardRemoval", "()V"); - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - TRACE("****** Init Native Structure OK ******"); - return TRUE; - -} - -/* Init/Deinit method */ -static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - int init_result = JNI_FALSE; -#ifdef TNFC_EMULATOR_ONLY - char value[PROPERTY_VALUE_MAX]; -#endif - jboolean result; - - CONCURRENCY_LOCK(); - -#ifdef TNFC_EMULATOR_ONLY - if (!property_get("ro.kernel.qemu", value, 0)) - { - ALOGE("NFC Initialization failed: not running in an emulator\n"); - goto clean_and_return; - } -#endif - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nat->seId = SMX_SECURE_ELEMENT_ID; - - nat->lto = 150; // LLCP_LTO - nat->miu = 128; // LLCP_MIU - // WKS indicates well-known services; 1 << sap for each supported SAP. - // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) - nat->wks = 0x13; // LLCP_WKS - nat->opt = 0; // LLCP_OPT - nat->p2p_initiator_modes = phNfc_eP2P_ALL; - nat->p2p_target_modes = 0x0E; // All passive except 106, active - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; - - nat->registry_info.MifareUL = TRUE; - nat->registry_info.MifareStd = TRUE; - nat->registry_info.ISO14443_4A = TRUE; - nat->registry_info.ISO14443_4B = TRUE; - nat->registry_info.Jewel = TRUE; - nat->registry_info.Felica = TRUE; - nat->registry_info.NFC = TRUE; - nat->registry_info.ISO15693 = TRUE; - - exported_nat = nat; - - /* Perform the initialization */ - init_result = nfc_jni_initialize(nat); - -clean_and_return: - CONCURRENCY_UNLOCK(); - - /* Convert the result and return */ - return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; -} - -static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) -{ - struct timespec ts; - NFCSTATUS status; - int result = JNI_FALSE; - struct nfc_jni_native_data *nat; - int bStackReset = FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Clear previous configuration */ - memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); - memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); - - /* Create the local semaphore */ - if (nfc_cb_data_init(&cb_data, NULL)) - { - TRACE("phLibNfc_Mgt_DeInitialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status == NFCSTATUS_PENDING) - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts) == -1) - { - ALOGW("Operation timed out"); - bStackReset = TRUE; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Failed to deinit the stack"); - bStackReset = TRUE; - } - } - else - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - bStackReset = TRUE; - } - nfc_cb_data_deinit(&cb_data); - } - else - { - ALOGE("Failed to create semaphore (errno=0x%08x)", errno); - bStackReset = TRUE; - } - - kill_client(nat); - - if(bStackReset == TRUE) - { - /* Complete deinit. failed, try hard restart of NFC */ - ALOGW("Reseting stack..."); - emergency_recovery(nat); - } - - result = nfc_jni_unconfigure_driver(nat); - - TRACE("NFC Deinitialized"); - - CONCURRENCY_UNLOCK(); - - return TRUE; -} - -/* Secure Element methods */ -static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { - NFCSTATUS ret; - jintArray list= NULL; - phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; - - TRACE("****** Get Secure Element List ******"); - - TRACE("phLibNfc_SE_GetSecureElementList()"); - REENTRANCE_LOCK(); - ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_SUCCESS) { - ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - return list; - } - TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - - TRACE("Nb SE: %d", se_count); - list =e->NewIntArray(se_count); - for (i = 0; i < se_count; i++) { - if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } - e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); - } - - e->DeleteLocalRef(list); - - return list; -} - -static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Select Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Virtual */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING) { - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Deselect Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Default */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, - nfc_jni_se_set_mode_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); - if (ret != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -/* Llcp methods */ - -static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - bool freeData = false; - jboolean result = JNI_FALSE; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data *cb_data; - - - CONCURRENCY_LOCK(); - - /* Memory allocation for cb_data - * This is on the heap because it is used by libnfc - * even after this call has succesfully finished. It is only freed - * upon link closure in nfc_jni_llcp_linkStatus_callback. - */ - cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(cb_data, (void*)nat)) - { - goto clean_and_return; - } - - /* Check LLCP compliancy */ - TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, - nfc_jni_checkLlcp_callback, - nfc_jni_llcp_linkStatus_callback, - (void*)cb_data); - REENTRANCE_UNLOCK(); - /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol - * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - freeData = true; - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data->sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data->status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(cb_data); - if (freeData) { - free(cb_data); - } - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Activate(hLlcpHandle); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_FALSE; - } -} - - - -static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, - jint nSap, jstring sn) -{ - NFCSTATUS ret; - jobject connectionlessSocket = NULL; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_native_data *nat; - phNfc_sData_t sWorkingBuffer = {NULL, 0}; - phNfc_sData_t serviceName = {NULL, 0}; - phLibNfc_Llcp_sLinkParameters_t sParams; - jclass clsNativeConnectionlessSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Allocate Working buffer length */ - phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); - sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, - NULL, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - - /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) - { - goto error; - } - - /* Get NativeConnectionless class object */ - clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); - if(e->ExceptionCheck()) - { - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); - e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); - TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); - - /* Set the miu link of the connectionless socket */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); - e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); - TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); - e->SetIntField(connectionlessSocket, f,(jint)nSap); - TRACE("Connectionless socket SAP = %d\n",nSap); - - return connectionlessSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - - if (sWorkingBuffer.buffer != NULL) { - free(sWorkingBuffer.buffer); - } - - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - phNfc_sData_t serviceName; - struct nfc_jni_native_data *nat; - jobject serviceSocket = NULL; - jclass clsNativeLlcpServiceSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - ret = phLibNfc_Llcp_Close(hLlcpSocket); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Listen( hLlcpSocket, - nfc_jni_llcp_transport_listen_socket_callback, - (void*)hLlcpSocket); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - /* Close created socket */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) - { - ALOGE("Llcp Socket object creation error"); - goto error; - } - - /* Get NativeLlcpServiceSocket class object */ - clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); - if(e->ExceptionCheck()) - { - ALOGE("Llcp Socket get object class error"); - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); - e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); - TRACE("Service socket Handle = %02x\n",hLlcpSocket); - - /* Set socket linear buffer length */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); - e->SetIntField(serviceSocket, f,(jint)linearBufferLength); - TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); - e->SetIntField(serviceSocket, f,(jint)miu); - TRACE("Service socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); - e->SetIntField(serviceSocket, f,(jint)rw); - TRACE("Service socket RW = %d\n",rw); - - return serviceSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) -{ - jobject clientSocket = NULL; - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - struct nfc_jni_native_data *nat; - jclass clsNativeLlcpSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - return NULL; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGE("Llcp socket object creation error"); - return NULL; - } - - /* Get NativeConnectionless class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGE("Get class object error"); - return NULL; - } - - /* Test if an SAP number is present */ - if(nSap != 0) - { - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - return NULL; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); - e->SetIntField(clientSocket, f,(jint)nSap); - TRACE("socket SAP = %d\n",nSap); - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hLlcpSocket); - TRACE("socket Handle = %02x\n",hLlcpSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - TRACE("socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - TRACE("socket RW = %d\n",rw); - - - return clientSocket; -} - -static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) -{ - TRACE("Last Error Status = 0x%02x",lastErrorStatus); - - if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) - { - return ERROR_BUFFER_TOO_SMALL; - } - else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) - { - return ERROR_INSUFFICIENT_RESOURCES; - } - else - { - return lastErrorStatus; - } -} - -static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) -{ - emergency_recovery(NULL); -} - -static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting init modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_initiator_modes = modes; -} - -static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting target modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_target_modes = modes; -} - -static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { - bool result = FALSE; - int load_result; - bool wasDisabled = FALSE; - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - NFCSTATUS status = NFCSTATUS_FAILED; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - result = FALSE; - goto clean_and_return; - } - - if (takeLock) - { - CONCURRENCY_LOCK(); - } - - /* Initialize Driver */ - if(!driverConfigured) - { - result = nfc_jni_configure_driver(nat); - wasDisabled = TRUE; - } - TRACE("com_android_nfc_NfcManager_doDownload()"); - - TRACE("Go in Download Mode"); - phLibNfc_Download_Mode(); - - TRACE("Load new Firmware Image"); - load_result = phLibNfc_Load_Firmware_Image(); - if(load_result != 0) - { - TRACE("Load new Firmware Image - status = %d",load_result); - result = FALSE; - goto clean_and_return; - } - - // Download - gInputParam.buffer = InputBuffer; - gInputParam.length = 0x01; - gOutputParam.buffer = OutputBuffer; - gOutputParam.length = 0x01; - - ALOGD("Download new Firmware"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - result = FALSE; - goto clean_and_return; - } - - /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we - try to download an old-style firmware on top of a new-style - firmware. Hence, this is expected behavior, and not an - error condition. */ - if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); - } - - /*Download is successful*/ - result = TRUE; -clean_and_return: - TRACE("phLibNfc_HW_Reset()"); - phLibNfc_HW_Reset(); - /* Deinitialize Driver */ - if(wasDisabled) - { - result = nfc_jni_unconfigure_driver(nat); - } - if (takeLock) - { - CONCURRENCY_UNLOCK(); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - return performDownload(nat, true); -} - -static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); - return e->NewStringUTF(buffer); -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doDownload", "()Z", - (void *)com_android_nfc_NfcManager_doDownload}, - - {"initializeNativeStructure", "()Z", - (void *)com_android_nfc_NfcManager_init_native_struc}, - - {"doInitialize", "()Z", - (void *)com_android_nfc_NfcManager_initialize}, - - {"doDeinitialize", "()Z", - (void *)com_android_nfc_NfcManager_deinitialize}, - - {"enableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_enableDiscovery}, - - {"doGetSecureElementList", "()[I", - (void *)com_android_nfc_NfcManager_doGetSecureElementList}, - - {"doSelectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doSelectSecureElement}, - - {"doDeselectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, - - {"doCheckLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doCheckLlcp}, - - {"doActivateLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doActivateLlcp}, - - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, - - {"doGetLastError", "()I", - (void *)com_android_nfc_NfcManager_doGetLastError}, - - {"disableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_disableDiscovery}, - - {"doSetTimeout", "(II)Z", - (void *)com_android_nfc_NfcManager_doSetTimeout}, - - {"doGetTimeout", "(I)I", - (void *)com_android_nfc_NfcManager_doGetTimeout}, - - {"doResetTimeouts", "()V", - (void *)com_android_nfc_NfcManager_doResetTimeouts}, - - {"doAbort", "()V", - (void *)com_android_nfc_NfcManager_doAbort}, - - {"doSetP2pInitiatorModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, - - {"doSetP2pTargetModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, - - {"doDump", "()Ljava/lang/String;", - (void *)com_android_nfc_NfcManager_doDump}, -}; - - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e) -{ - nfc_jni_native_monitor_t *nfc_jni_native_monitor; - - nfc_jni_native_monitor = nfc_jni_init_monitor(); - if(nfc_jni_native_monitor == NULL) - { - ALOGE("NFC Manager cannot recover native monitor %x\n", errno); - return -1; - } - - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", - gMethods, NELEM(gMethods)); -} - -} /* namespace android */ diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp deleted file mode 100755 index bf0bffc..0000000 --- a/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "com_android_nfc.h" - -static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; -static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; -static phNfc_sRemoteDevInformation_t* SecureElementInfo; -static int secureElementHandle; -extern void *gHWRef; -static int SecureElementTech; -extern uint8_t device_connected_flag; - -namespace android { - -static void com_android_nfc_jni_ioctl_callback ( void* pContext, - phNfc_sData_t* Outparam_Cb, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if (status == NFCSTATUS_SUCCESS ) - { - LOG_CALLBACK("> IOCTL successful",status); - } - else - { - LOG_CALLBACK("> IOCTL error",status); - } - - com_android_nfc_jni_ioctl_buffer = Outparam_Cb; - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); - - com_android_nfc_jni_transceive_buffer = pResBuffer; - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static void com_android_nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if(status==NFCSTATUS_SUCCESS) - { - LOG_CALLBACK("SE Set Mode is Successful",status); - TRACE("SE Handle: %lu", hSecureElement); - } - else - { - LOG_CALLBACK("SE Set Mode is failed\n ",status); - } - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - NFCSTATUS ret; - int i; - JNIEnv *e = nfc_get_env(); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); - } - else - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); - TRACE("Discovered %d secure elements", uNofRemoteDev); - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - bool foundHandle = false; - TRACE("Multiple Protocol supported\n"); - for (i=0; iRemDevType); - if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { - secureElementHandle = psRemoteDevList[i].hTargetDev; - foundHandle = true; - } - } - if (!foundHandle) { - ALOGE("Could not find ISO-DEP secure element"); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - } - else - { - secureElementHandle = psRemoteDevList->hTargetDev; - } - - TRACE("Secure Element Handle: 0x%08x", secureElementHandle); - - /* Set type name */ - jintArray techList; - nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); - - // TODO: Should use the "connected" technology, for now use the first - if ((techList != NULL) && e->GetArrayLength(techList) > 0) { - e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); - TRACE("Store Secure Element Info\n"); - SecureElementInfo = psRemoteDevList->psRemoteDevInfo; - - TRACE("Discovered secure element: tech=%d", SecureElementTech); - } - else { - ALOGE("Discovered secure element, but could not resolve tech"); - status = NFCSTATUS_FAILED; - } - - // This thread may not return to the virtual machine for a long time - // so make sure to delete the local refernce to the tech list. - e->DeleteLocalRef(techList); - } - -clean_and_return: - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - int semResult; - - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - uint8_t Output_Buff[10]; - uint8_t reg_value; - uint8_t mask_value; - struct nfc_jni_callback_data cb_data; - struct nfc_jni_callback_data cb_data_SE_Notification; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) - { - goto clean_and_return; - } - - /* Registery */ - registry_info.MifareUL = TRUE; - registry_info.MifareStd = TRUE; - registry_info.ISO14443_4A = TRUE; - registry_info.ISO14443_4B = TRUE; - registry_info.Jewel = TRUE; - registry_info.Felica = TRUE; - registry_info.NFC = FALSE; - - CONCURRENCY_LOCK(); - - TRACE("Open Secure Element"); - - /* Check if NFC device is already connected to a tag or P2P peer */ - if (device_connected_flag == 1) - { - ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); - goto clean_and_return; - } - - /* Test if External RF field is detected */ - InParam.buffer = ExternalRFDetected; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - /* Check the value */ - reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; - mask_value = reg_value & 0x40; - - if(mask_value == 0x40) - { - // There is an external RF field present, fail the open request - ALOGD("Unable to open SE connection, external RF Field detected"); - goto clean_and_return; - } - - /* Get Secure Element List */ - TRACE("phLibNfc_SE_GetSecureElementList()"); - ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); - if (ret == NFCSTATUS_SUCCESS) - { - TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i SMX detected"); - TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); - /* save SMARTMX index */ - SmartMX_detected = 1; - SmartMX_index = i; - } - } - - if(SmartMX_detected) - { - REENTRANCE_LOCK(); - TRACE("phLibNfc_RemoteDev_NtfRegister()"); - ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, - com_android_nfc_jni_open_secure_element_notification_callback, - (void *)&cb_data_SE_Notification); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("Register Notification error"); - goto clean_and_return; - } - - /* Set wired mode */ - REENTRANCE_LOCK(); - TRACE("phLibNfc_SE_SetMode: Wired mode"); - ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, - phLibNfc_SE_ActModeWired, - com_android_nfc_jni_smartMX_setModeCb, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING ) - { - ALOGE("\n> SE Set SmartMX mode ERROR \n" ); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("SE set mode failed"); - goto clean_and_return; - } - - TRACE("Waiting for notification"); - /* Wait for callback response */ - if(sem_wait(&cb_data_SE_Notification.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && - cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) - { - ALOGE("SE detection failed"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Connect Tag */ - CONCURRENCY_LOCK(); - TRACE("phLibNfc_RemoteDev_Connect(SMX)"); - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("CONNECT semaphore error"); - goto clean_and_return; - } - - /* Connect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Secure Element connect error"); - goto clean_and_return; - } - - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue | 0x40); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - /* Return the Handle of the SecureElement */ - return secureElementHandle; - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); - goto clean_and_return; - } - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - CONCURRENCY_UNLOCK(); - return 0; -} - - -static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) -{ - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - uint32_t SmartMX_Handle; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t Output_Buff[10]; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Close Secure element function "); - - CONCURRENCY_LOCK(); - /* Disconnect */ - TRACE("Disconnecting from SMX (handle = 0x%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, - NFC_SMARTMX_RELEASE, - com_android_nfc_jni_disconnect_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("\n> Disconnect SE ERROR \n" ); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue & 0xBF); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, - jobject o,jint handle, jbyteArray data) -{ - uint8_t offset = 0; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - - int tech = SecureElementTech; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Exchange APDU function "); - - CONCURRENCY_LOCK(); - - TRACE("Secure Element tech: %d\n", tech); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - /* Prepare transceive info structure */ - if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) - { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - else if(tech == TARGET_TYPE_ISO14443_4) - { - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - } - - transceive_info.sSendData.buffer = buf + offset; - transceive_info.sSendData.length = buflen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - com_android_nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("TRANSCEIVE semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("TRANSCEIVE error"); - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); - if(result != NULL) - { - e->SetByteArrayRegion(result, 0, - com_android_nfc_jni_transceive_buffer->length, - (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) -{ - TRACE("Get Secure element UID function "); - jbyteArray SecureElementUid; - - if(handle == secureElementHandle) - { - SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); - e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); - return SecureElementUid; - } - else - { - return NULL; - } -} - -static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) -{ - jintArray techList; - TRACE("Get Secure element Type function "); - - if(handle == secureElementHandle) - { - techList = e->NewIntArray(1); - e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); - return techList; - } - else - { - return NULL; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doNativeOpenSecureElementConnection", "()I", - (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, - {"doNativeDisconnectSecureElementConnection", "(I)Z", - (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, - {"doTransceive", "(I[B)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, - {"doGetUid", "(I)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, - {"doGetTechList", "(I)[I", - (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, -}; - -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp deleted file mode 100644 index dbf8dc9..0000000 --- a/jni/com_android_nfc_NativeNfcTag.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" -#include "phNfcHalTypes.h" - -static phLibNfc_Data_t nfc_jni_ndef_rw; -static phLibNfc_Handle handle; -uint8_t *nfc_jni_ndef_buf = NULL; -uint32_t nfc_jni_ndef_buf_len = 0; - -extern uint8_t device_connected_flag; - -namespace android { - -extern phLibNfc_Handle storedHandle; - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); -extern void nfc_jni_reset_timeout_values(); - -/* - * Callbacks - */ - static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_tag_rw_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - if (pCallbackData->pContext != NULL) { - // Store the remote dev info ptr in the callback context - // Note that this ptr will remain valid, it is tied to a statically - // allocated buffer in libnfc. - phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = - (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; - *ppRemoteDevInfo = psRemoteDevInfo; - } - - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_checkndef_callback(void *pContext, - phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_checkndef_callback", status); - phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); - if(status == NFCSTATUS_OK) - { - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; - nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); - if (pNdefInfo != NULL) *pNdefInfo = info; - } - else { - if (pNdefInfo != NULL) { - memset(pNdefInfo, 0, sizeof(*pNdefInfo)); - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_async_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; -} - -static phNfc_sData_t *nfc_jni_transceive_buffer; - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - nfc_jni_transceive_buffer = pResBuffer; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presencecheck_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_formatndef_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_readonly_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* Functions */ -static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, - jobject o) -{ - NFCSTATUS status; - phLibNfc_Handle handle = 0; - jbyteArray buf = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; - nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; - - TRACE("phLibNfc_Ndef_Read()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, - phLibNfc_Ndef_EBegin, - nfc_jni_tag_rw_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - buf = e->NewByteArray(nfc_jni_ndef_rw.length); - e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, - (jbyte *)nfc_jni_ndef_rw.buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - - return buf; -} - - -static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, - jobject o, jbyteArray buf) -{ - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); - nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_Ndef_Write()"); - TRACE("Ndef Handle :0x%x\n",handle); - TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * Utility to recover poll bytes from target infos - */ -static void set_target_pollBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); - - jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingPollBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - jint *techId = e->GetIntArrayElements(techList, 0); - int techListLength = e->GetArrayLength(techList); - - jbyteArray pollBytes = e->NewByteArray(0); - jobjectArray techPollBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(pollBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) - { - /* ISO14443-3A: ATQA/SENS_RES */ - case TARGET_TYPE_ISO14443_3A: - if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { - // Jewel ATQA is not read and stored by the PN544, but it is fixed - // at {0x00, 0x0C} in the spec. So eJewel can safely be - // translated to {0x00, 0x0C}. - const static jbyte JewelAtqA[2] = {0x00, 0x0C}; - pollBytes = e->NewByteArray(2); - e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); - } - else { - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); - } - break; - /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ - case TARGET_TYPE_ISO14443_3B: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); - break; - /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ - case TARGET_TYPE_FELICA: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - pollBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techPollBytes, tech, pollBytes); - } - - e->SetObjectField(tag, f, techPollBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); - -} - -/* - * Utility to recover activation bytes from target infos - */ -static void set_target_activationBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - - jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); - jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingActBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - int techListLength = e->GetArrayLength(techList); - jint *techId = e->GetIntArrayElements(techList, 0); - - jbyteArray actBytes = e->NewByteArray(0); - jobjectArray techActBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(actBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) { - - /* ISO14443-3A: SAK/SEL_RES */ - case TARGET_TYPE_ISO14443_3A: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); - break; - /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ - /* ISO14443-3B & ISO14443-4: HiLayerResp */ - case TARGET_TYPE_ISO14443_4: - // Determine whether -A or -B - if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); - e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); - } - else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); - e->SetByteArrayRegion(actBytes, 0, - psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); - } - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - actBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techActBytes, tech, actBytes); - } - e->SetObjectField(tag, f, techActBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); -} - -static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - // Success, set poll & act bytes - set_target_pollBytes(e, o, pRemDevInfo); - set_target_activationBytes(e, o, pRemDevInfo); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, - jobject o) -{ - // Reconnect is provided by libnfc by just calling connect again - // on the same handle. - int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - if (libNfcType != -1) { - // Note that some tag types are stateless, hence we do not reconnect - // those. Currently those are the Jewel and Iso15693 technologies. - if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); - return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); - } - else { - return NFCSTATUS_SUCCESS; - } - } - else { - return NFCSTATUS_REJECTED; - } -} - - -static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_connected_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Reset the stored handle */ - storedHandle = 0; - - nfc_jni_reset_timeout_values(); - - /* Disconnect */ - TRACE("Disconnecting from tag (%x)", handle); - - if (handle == -1) { - // Was never connected to any tag, exit - result = JNI_TRUE; - ALOGE("doDisconnect() - Target already disconnected"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, - nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - result = JNI_TRUE; - TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); - goto clean_and_return; - } - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static uint16_t -crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) -{ - uint16_t b, crc = init; - - do { - b = *msg++ ^ (crc & 0xFF); - b ^= (b << 4) & 0xFF; - crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); - } while( --len ); - - return crc; -} - -static void -nfc_insert_crc_a( uint8_t* msg, size_t len ) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - msg[len] = crc & 0xFF; - msg[len + 1] = (crc >> 8) & 0xFF; -} - -static void -nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - *byte1 = crc & 0xFF; - *byte2 = (crc >> 8) & 0xFF; -} - -static bool -crc_valid( uint8_t* msg, size_t len) -{ - uint8_t crcByte1, crcByte2; - - nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, - len - 2, &crcByte1, &crcByte2); - - if (msg[len - 2] == crcByte1 && - msg[len - 1] == crcByte2) { - return true; - } - else { - return false; - } - -} - -static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, - jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) -{ - uint8_t offset = 0; - // buf is the pointer to the JNI array and never overwritten, - // outbuf is passed into the transceive - it may be pointed to new memory - // to be extended with CRC. - uint8_t *buf = NULL; - uint32_t buflen; - - uint8_t *outbuf = NULL; - uint32_t outlen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - int selectedTech = 0; - int selectedLibNfcType = 0; - jint* technologies = NULL; - bool checkResponseCrc = false; - - jint *targetLost; - if (statusTargetLost != NULL) { - targetLost = e->GetIntArrayElements(statusTargetLost, 0); - if (targetLost != NULL) { - *targetLost = 0; - } - } else { - targetLost = NULL; - } - - memset(&transceive_info, 0, sizeof(transceive_info)); - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - selectedTech = nfc_jni_get_connected_technology(e, o); - selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - - buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = outlen = (uint32_t)e->GetArrayLength(data); - - switch (selectedTech) { - case TARGET_TYPE_FELICA: - transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - if (raw) { - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - break; - case TARGET_TYPE_ISO14443_3A: - // Check which libnfc type - if (selectedLibNfcType == phNfc_eJewel_PICC) { - // For the Jewel pipe, CRC is automatically computed - transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; - transceive_info.addr = 0; - } else { - if (raw) { - // Use Mifare Raw to implement a standard - // ISO14443-3A transceive, with CRC added - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - // Use the mifare pipe - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - - } - break; - case TARGET_TYPE_ISO14443_4: - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_ISO15693: - transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; - transceive_info.addr = 0; - break; - case TARGET_TYPE_UNKNOWN: - case TARGET_TYPE_ISO14443_3B: - // Not supported - goto clean_and_return; - default: - break; - } - - transceive_info.sSendData.buffer = outbuf + offset; - transceive_info.sSendData.length = outlen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - - /* Copy results back to Java * - * In case of NfcA and raw, also check the CRC in the response - * and cut it off in the returned data. - */ - if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { - if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { - result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length - 2, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } - } else { - result = e->NewByteArray(nfc_jni_transceive_buffer->length); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - if ((outbuf != buf) && (outbuf != NULL)) { - // Buf was extended and re-alloced with crc bytes, free separately - free(outbuf); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)buf, JNI_ABORT); - - if (targetLost != NULL) { - e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); - } - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, - jint libnfcType, jint javaType) -{ - jint ndefType = NDEF_UNKNOWN_TYPE; - - switch (libnfcType) { - case phNfc_eJewel_PICC: - ndefType = NDEF_TYPE1_TAG; - break; - case phNfc_eISO14443_3A_PICC: - ndefType = NDEF_TYPE2_TAG;; - break; - case phNfc_eFelica_PICC: - ndefType = NDEF_TYPE3_TAG; - break; - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - ndefType = NDEF_TYPE4_TAG; - break; - case phNfc_eMifare_PICC: - if (javaType == TARGET_TYPE_MIFARE_UL) { - ndefType = NDEF_TYPE2_TAG; - } else { - ndefType = NDEF_MIFARE_CLASSIC_TAG; - } - break; - case phNfc_eISO15693_PICC: - ndefType = NDEF_ICODE_SLI_TAG; - break; - default: - ndefType = NDEF_UNKNOWN_TYPE; - break; - } - return ndefType; -} - -static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) -{ - phLibNfc_Handle handle = 0; - jint status; - phLibNfc_ChkNdef_Info_t sNdefInfo; - struct nfc_jni_callback_data cb_data; - jint *ndef = e->GetIntArrayElements(ndefinfo, 0); - int apiCardState = NDEF_MODE_UNKNOWN; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - cb_data.pContext = &sNdefInfo; - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_Ndef_CheckNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); - - if (status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ndef[0] = sNdefInfo.MaxNdefMsgLength; - // Translate the card state to know values for the NFC API - switch (sNdefInfo.NdefCardState) { - case PHLIBNFC_NDEF_CARD_INITIALISED: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_READ_ONLY: - apiCardState = NDEF_MODE_READ_ONLY; - break; - case PHLIBNFC_NDEF_CARD_READ_WRITE: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_INVALID: - apiCardState = NDEF_MODE_UNKNOWN; - break; - } - ndef[1] = apiCardState; - -clean_and_return: - e->ReleaseIntArrayElements(ndefinfo, ndef, 0); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_RemoteDev_CheckPresence()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, - jobject o, jbyteArray pollBytes, jbyteArray actBytes) -{ - // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire - // is supported. - jboolean result = JNI_FALSE; - - // DESfire has one sak byte and 2 ATQA bytes - if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && - actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { - jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); - jbyte* act = e->GetByteArrayElements(actBytes, NULL); - if (act[0] == 0x20 && poll[1] == 0x03) { - uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; - // Identifies as DESfire, use get version cmd to be sure - jbyteArray versionCmd = e->NewByteArray(5); - e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); - jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, - versionCmd, JNI_TRUE, NULL); - if (respBytes != NULL) { - // Check whether the response matches a typical DESfire - // response. - // libNFC even does more advanced checking than we do - // here, and will only format DESfire's with a certain - // major/minor sw version and NXP as a manufacturer. - // We don't want to do such checking here, to avoid - // having to change code in multiple places. - // A succesful (wrapped) DESFire getVersion command returns - // 9 bytes, with byte 7 0x91 and byte 8 having status - // code 0xAF (these values are fixed and well-known). - int respLength = e->GetArrayLength(respBytes); - jbyte* resp = e->GetByteArrayElements(respBytes, NULL); - if (respLength == 9 && resp[7] == (jbyte)0x91 && - resp[8] == (jbyte)0xAF) { - result = JNI_TRUE; - } - e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); - } - } - e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); - e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); - } - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - phNfc_sData_t keyBuffer; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_RemoteDev_FormatNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t keyBuffer; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_ConvertToReadOnlyNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeNfcTag_doDisconnect}, - {"doReconnect", "()I", - (void *)com_android_nfc_NativeNfcTag_doReconnect}, - {"doHandleReconnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, - {"doTransceive", "([BZ[I)[B", - (void *)com_android_nfc_NativeNfcTag_doTransceive}, - {"doGetNdefType", "(II)I", - (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, - {"doCheckNdef", "([I)I", - (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, - {"doRead", "()[B", - (void *)com_android_nfc_NativeNfcTag_doRead}, - {"doWrite", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doWrite}, - {"doPresenceCheck", "()Z", - (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, - {"doIsIsoDepNdefFormatable", "([B[B)Z", - (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, - {"doNdefFormat", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, - {"doMakeReadonly", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, -}; - -int register_com_android_nfc_NativeNfcTag(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp deleted file mode 100644 index b3cc6e3..0000000 --- a/jni/com_android_nfc_NativeP2pDevice.cpp +++ /dev/null @@ -1,490 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -extern uint8_t device_connected_flag; - -namespace android { - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); - -/* - * Callbacks - */ -static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presence_check_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; - psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_receive_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - *ptr = data; - } - else - { - *ptr = NULL; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Functions - */ - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - /* Report the callback data and wake up the caller */ - pCallbackData->pContext = pResBuffer; - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - jclass target_cls = NULL; - jobject tag; - jmethodID ctor; - jfieldID f; - jbyteArray generalBytes = NULL; - phNfc_sData_t sGeneralBytes; - unsigned int i; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Set General Bytes */ - target_cls = e->GetObjectClass(o); - - f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes Length = %d", sGeneralBytes.length); - TRACE("General Bytes ="); - for(i=0;iNewByteArray(sGeneralBytes.length); - - e->SetByteArrayRegion(generalBytes, 0, - sGeneralBytes.length, - (jbyte *)sGeneralBytes.buffer); - - e->SetObjectField(o, f, generalBytes); - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - /* Restart the polling loop if the connection failed */ - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jboolean result = JNI_FALSE; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Disconnect */ - TRACE("Disconnecting from target (handle = 0x%x)", handle); - - /* NativeNfcTag waits for tag to leave the field here with presence check. - * We do not in P2P path because presence check is not safe while transceive may be - * in progress. - */ - - TRACE("phLibNfc_RemoteDev_Disconnect()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); - } - else - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, - jobject o, jbyteArray data) -{ - NFCSTATUS status; - uint8_t offset = 2; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - phNfc_sData_t * receive_buffer = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) - { - goto clean_and_return; - } - - /* Transceive*/ - TRACE("Transceive data to target (handle = 0x%x)", handle); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - TRACE("Buffer Length = %d\n", buflen); - - transceive_info.sSendData.buffer = buf; //+ offset; - transceive_info.sSendData.length = buflen; //- offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(receive_buffer->length); - if(result != NULL) - e->SetByteArrayRegion(result, 0, - receive_buffer->length, - (jbyte *)receive_buffer->buffer); - -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - - -static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( - JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct timespec ts; - phLibNfc_Handle handle; - jbyteArray buf = NULL; - static phNfc_sData_t *data; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)data)) - { - goto clean_and_return; - } - - /* Receive */ - TRACE("phLibNfc_RemoteDev_Receive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(data == NULL) - { - goto clean_and_return; - } - - buf = e->NewByteArray(data->length); - e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return buf; -} - -static jboolean com_android_nfc_NativeP2pDevice_doSend( - JNIEnv *e, jobject o, jbyteArray buf) -{ - NFCSTATUS status; - phNfc_sData_t data; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Send */ - TRACE("Send data to the Initiator (handle = 0x%x)", handle); - - data.length = (uint32_t)e->GetArrayLength(buf); - data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_RemoteDev_Send()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, - {"doTransceive", "([B)[B", - (void *)com_android_nfc_NativeP2pDevice_doTransceive}, - {"doReceive", "()[B", - (void *)com_android_nfc_NativeP2pDevice_doReceive}, - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeP2pDevice_doSend}, -}; - -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", - gMethods, NELEM(gMethods)); -} - -} // namepspace android diff --git a/jni/com_android_nfc_list.cpp b/jni/com_android_nfc_list.cpp deleted file mode 100644 index f0487d3..0000000 --- a/jni/com_android_nfc_list.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#undef LOG_TAG -#define LOG_TAG "NFC_LIST" - -bool listInit(listHead* pList) -{ - pList->pFirst = NULL; - if(pthread_mutex_init(&pList->mutex, NULL) == -1) - { - ALOGE("Mutex creation failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listDestroy(listHead* pList) -{ - bool bListNotEmpty = true; - while (bListNotEmpty) { - bListNotEmpty = listGetAndRemoveNext(pList, NULL); - } - - if(pthread_mutex_destroy(&pList->mutex) == -1) - { - ALOGE("Mutex destruction failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listAdd(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pLastNode; - bool result; - - /* Create node */ - pNode = (struct listNode*)malloc(sizeof(listNode)); - if (pNode == NULL) - { - result = false; - ALOGE("Failed to malloc"); - goto clean_and_return; - } - TRACE("Allocated node: %8p (%8p)", pNode, pData); - pNode->pData = pData; - pNode->pNext = NULL; - - pthread_mutex_lock(&pList->mutex); - - /* Add the node to the list */ - if (pList->pFirst == NULL) - { - /* Set the node as the head */ - pList->pFirst = pNode; - } - else - { - /* Seek to the end of the list */ - pLastNode = pList->pFirst; - while(pLastNode->pNext != NULL) - { - pLastNode = pLastNode->pNext; - } - - /* Add the node to the current list */ - pLastNode->pNext = pNode; - } - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listRemove(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pRemovedNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst == NULL) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - pNode = pList->pFirst; - if (pList->pFirst->pData == pData) - { - /* Get the removed node */ - pRemovedNode = pNode; - - /* Remove the first node */ - pList->pFirst = pList->pFirst->pNext; - } - else - { - while (pNode->pNext != NULL) - { - if (pNode->pNext->pData == pData) - { - /* Node found ! */ - break; - } - pNode = pNode->pNext; - } - - if (pNode->pNext == NULL) - { - /* Node not found */ - result = false; - ALOGE("Failed to deallocate (not found %8p)", pData); - goto clean_and_return; - } - - /* Get the removed node */ - pRemovedNode = pNode->pNext; - - /* Remove the node from the list */ - pNode->pNext = pNode->pNext->pNext; - } - - /* Deallocate the node */ - TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); - free(pRemovedNode); - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listGetAndRemoveNext(listHead* pList, void** ppData) -{ - struct listNode* pNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - /* Work on the first node */ - pNode = pList->pFirst; - - /* Return the data */ - if (ppData != NULL) - { - *ppData = pNode->pData; - } - - /* Remove and deallocate the node */ - pList->pFirst = pNode->pNext; - TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); - free(pNode); - - result = true; - -clean_and_return: - listDump(pList); - pthread_mutex_unlock(&pList->mutex); - return result; -} - -void listDump(listHead* pList) -{ - struct listNode* pNode = pList->pFirst; - - TRACE("Node dump:"); - while (pNode != NULL) - { - TRACE("- %8p (%8p)", pNode, pNode->pData); - pNode = pNode->pNext; - } -} diff --git a/jni/com_android_nfc_list.h b/jni/com_android_nfc_list.h deleted file mode 100644 index 22b4f09..0000000 --- a/jni/com_android_nfc_list.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_LIST_H__ -#define __COM_ANDROID_NFC_LIST_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct listNode -{ - void* pData; - struct listNode* pNext; -}; - -struct listHead -{ - listNode* pFirst; - pthread_mutex_t mutex; -}; - -bool listInit(listHead* pList); -bool listDestroy(listHead* pList); -bool listAdd(listHead* pList, void* pData); -bool listRemove(listHead* pList, void* pData); -bool listGetAndRemoveNext(listHead* pList, void** ppData); -void listDump(listHead* pList); - -#ifdef __cplusplus -} -#endif - -#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/nxp/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/nxp/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h new file mode 100644 index 0000000..b876dad --- /dev/null +++ b/nxp/jni/com_android_nfc.h @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include +#include + +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) + #define TRACE_ENABLED 1 +#else + #define LOG_CALLBACK(...) + #define TRACE(...) + #define TRACE_ENABLED 0 +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..e6da0fa --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2623 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "com_android_nfc.h" + +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +extern uint32_t libnfc_llc_error_count; + +static phLibNfc_sConfig_t gDrvCfg; +void *gHWRef; +static phNfc_sData_t gInputParam; +static phNfc_sData_t gOutputParam; + +uint8_t device_connected_flag; +static bool driverConfigured = FALSE; + +static phLibNfc_Handle hLlcpHandle; +static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; +static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; + +static jmethodID cached_NfcManager_notifyNdefMessageListeners; +static jmethodID cached_NfcManager_notifyTransactionListeners; +static jmethodID cached_NfcManager_notifyLlcpLinkActivation; +static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; +static jmethodID cached_NfcManager_notifyTargetDeselected; + +static jmethodID cached_NfcManager_notifySeFieldActivated; +static jmethodID cached_NfcManager_notifySeFieldDeactivated; + +static jmethodID cached_NfcManager_notifySeApduReceived; +static jmethodID cached_NfcManager_notifySeMifareAccess; +static jmethodID cached_NfcManager_notifySeEmvCardRemoval; + +namespace android { + +phLibNfc_Handle storedHandle = 0; + +struct nfc_jni_native_data *exported_nat = NULL; + +/* Internal functions declaration */ +static void *nfc_jni_client_thread(void *arg); +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_se_set_mode_callback(void *context, + phLibNfc_Handle handle, NFCSTATUS status); +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status); +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); +static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); + +/* + * Deferred callback called when client thread must be exited + */ +static void client_kill_deferred_call(void* arg) +{ + struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; + + nat->running = FALSE; +} + +static void kill_client(nfc_jni_native_data *nat) +{ + phDal4Nfc_Message_Wrapper_t wrapper; + phLibNfc_DeferredCall_t *pMsg; + + usleep(50000); + + ALOGD("Terminating client thread..."); + + pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); + pMsg->pCallback = client_kill_deferred_call; + pMsg->pParameter = (void*)nat; + + wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + wrapper.msg.pMsgData = pMsg; + wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); + + phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); +} + +static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_ioctl_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_deinit_download_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) +{ + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + struct timespec ts; + NFCSTATUS status = NFCSTATUS_FAILED; + phLibNfc_StackCapabilities_t caps; + struct nfc_jni_callback_data cb_data; + bool result; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + if(update) + { + //deinit + TRACE("phLibNfc_Mgt_DeInitialize() (download)"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts)) + { + ALOGW("Deinitialization timed out (download)"); + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("Deinitialization FAILED (download)"); + } + TRACE("Deinitialization SUCCESS (download)"); + } + + result = performDownload(nat, false); + + if (!result) { + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + status = cb_data.status; + goto clean_and_return; + } + + /* ====== CAPABILITIES ======= */ + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /*Download is successful*/ + status = NFCSTATUS_SUCCESS; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return status; +} + +static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) +{ + char value[PROPERTY_VALUE_MAX]; + int result = FALSE; + NFCSTATUS status; + + /* ====== CONFIGURE DRIVER ======= */ + /* Configure hardware link */ + gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); + + TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); + REENTRANCE_UNLOCK(); + if(status == NFCSTATUS_ALREADY_INITIALISED) { + ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) + { + ALOGE("pthread_create failed"); + goto clean_and_return; + } + + driverConfigured = TRUE; + +clean_and_return: + return result; +} + +static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) +{ + int result = FALSE; + NFCSTATUS status; + + /* Unconfigure driver */ + TRACE("phLibNfc_Mgt_UnConfigureDriver()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); + } + else + { + ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = TRUE; + } + + driverConfigured = FALSE; + + return result; +} + +/* Initialization function */ +static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { + struct timespec ts; + uint8_t resp[16]; + NFCSTATUS status; + phLibNfc_StackCapabilities_t caps; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; + phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; + struct nfc_jni_callback_data cb_data; + uint8_t firmware_status; + uint8_t update = TRUE; + int result = JNI_FALSE; + const hw_module_t* hw_module; + nfc_pn544_device_t* pn544_dev = NULL; + int ret = 0; + ALOGD("Start Initialization\n"); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Get EEPROM values and device port from product-specific settings */ + ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); + if (ret) { + ALOGE("hw_get_module() failed."); + goto clean_and_return; + } + ret = nfc_pn544_open(hw_module, &pn544_dev); + if (ret) { + ALOGE("Could not open pn544 hw_module."); + goto clean_and_return; + } + if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { + ALOGE("Could not load EEPROM settings"); + goto clean_and_return; + } + + /* Reset device connected handle */ + device_connected_flag = 0; + + /* Reset stored handle */ + storedHandle = 0; + + /* Initialize Driver */ + if(!driverConfigured) + { + nfc_jni_configure_driver(nat); + } + + /* ====== INITIALIZE ======= */ + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + update = FALSE; + goto force_download; + } + TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + update = FALSE; + goto force_download; + } + + /* ====== CAPABILITIES ======= */ + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /* ====== FIRMWARE VERSION ======= */ + if(caps.psDevCapabilities.firmware_update_info) + { +force_download: + for (i=0; i<3; i++) + { + TRACE("Firmware version not UpToDate"); + status = nfc_jni_download_locked(nat, update); + if(status == NFCSTATUS_SUCCESS) + { + ALOGI("Firmware update SUCCESS"); + break; + } + ALOGW("Firmware update FAILED"); + update = FALSE; + } + if(i>=3) + { + ALOGE("Unable to update firmware, giving up"); + goto clean_and_return; + } + } + else + { + TRACE("Firmware version UpToDate"); + } + /* ====== EEPROM SETTINGS ======= */ + + // Update EEPROM settings + TRACE("****** START EEPROM SETTINGS UPDATE ******"); + for (i = 0; i < pn544_dev->num_eeprom_settings; i++) + { + char eeprom_property[PROPERTY_KEY_MAX]; + char eeprom_value[PROPERTY_VALUE_MAX]; + uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); + TRACE("> EEPROM SETTING: %d", i); + + // Check for override of this EEPROM value in properties + snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", + eeprom_base[1], eeprom_base[2]); + TRACE(">> Checking property: %s", eeprom_property); + if (property_get(eeprom_property, eeprom_value, "") == 2) { + int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); + ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", + eeprom_base[1], eeprom_base[2], eeprom_value_num); + eeprom_base[3] = eeprom_value_num; + } + + TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], + eeprom_base[3]); + gInputParam.buffer = eeprom_base; + gInputParam.length = 0x04; + gOutputParam.buffer = resp; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if (cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + } + TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); + + /* ====== SECURE ELEMENTS ======= */ + + REENTRANCE_LOCK(); + ALOGD("phLibNfc_SE_GetSecureElementList()"); + status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + + ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i < No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); + } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); + } + + /* Set SE mode - Off */ + REENTRANCE_LOCK(); + status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, + phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + } + + /* ====== LLCP ======= */ + + /* LLCP Params */ + TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); + LlcpConfigInfo.miu = nat->miu; + LlcpConfigInfo.lto = nat->lto; + LlcpConfigInfo.wks = nat->wks; + LlcpConfigInfo.option = nat->opt; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, + nfc_jni_llcpcfg_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* ===== DISCOVERY ==== */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.Duration = 300000; /* in ms */ + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== END ======= */ + + ALOGI("NFC Initialized"); + + result = TRUE; + +clean_and_return: + if (result != TRUE) + { + if(nat) + { + kill_client(nat); + } + } + if (pn544_dev != NULL) { + nfc_pn544_close(pn544_dev); + } + nfc_cb_data_deinit(&cb_data); + + return result; +} + +static int is_user_build() { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", value, ""); + return !strncmp("user", value, PROPERTY_VALUE_MAX); +} + +/* + * Last-chance fallback when there is no clean way to recover + * Performs a software reset + */ +void emergency_recovery(struct nfc_jni_native_data *nat) { + if (!is_user_build()) { + ALOGE("emergency_recovery: force restart of NFC service"); + } else { + // dont recover immediately, so we can debug + unsigned int t; + for (t=1; t < 1000000; t <<= 1) { + ALOGE("emergency_recovery: NFC stack dead-locked"); + sleep(t); + } + } + phLibNfc_Mgt_Recovery(); + abort(); // force a noisy crash +} + +void nfc_jni_reset_timeout_values() +{ + REENTRANCE_LOCK(); + phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); + phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); + phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); + phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); + REENTRANCE_UNLOCK(); +} + +/* + * Restart the polling loop when unable to perform disconnect + */ +void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) +{ + nfc_jni_start_discovery_locked(nat, true); +} + + /* + * Utility to recover UID from target infos + */ +static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + phNfc_sData_t uid; + + switch(psRemoteDevInfo->RemDevType) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_3A_PICC: + case phNfc_eMifare_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; + break; + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; + uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); + break; + case phNfc_eFelica_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; + uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; + break; + case phNfc_eJewel_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; + break; + case phNfc_eISO15693_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; + break; + case phNfc_eNfcIP1_Target: + case phNfc_eNfcIP1_Initiator: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; + uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; + break; + default: + uid.buffer = NULL; + uid.length = 0; + break; + } + + return uid; +} + +/* + * NFC stack message processing + */ +static void *nfc_jni_client_thread(void *arg) +{ + struct nfc_jni_native_data *nat; + JNIEnv *e; + JavaVMAttachArgs thread_args; + phDal4Nfc_Message_Wrapper_t wrapper; + + nat = (struct nfc_jni_native_data *)arg; + + thread_args.name = "NFC Message Loop"; + thread_args.version = nat->env_version; + thread_args.group = NULL; + + nat->vm->AttachCurrentThread(&e, &thread_args); + pthread_setname_np(pthread_self(), "message"); + + TRACE("NFC client started"); + nat->running = TRUE; + while(nat->running == TRUE) + { + /* Fetch next message from the NFC stack message queue */ + if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, + sizeof(phLibNfc_Message_t), 0, 0) == -1) + { + ALOGE("NFC client received bad message"); + continue; + } + + switch(wrapper.msg.eMsgType) + { + case PH_LIBNFC_DEFERREDCALL_MSG: + { + phLibNfc_DeferredCall_t *msg = + (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); + + REENTRANCE_LOCK(); + msg->pCallback(msg->pParameter); + REENTRANCE_UNLOCK(); + + break; + } + } + } + TRACE("NFC client stopped"); + + nat->vm->DetachCurrentThread(); + + return NULL; +} + +extern uint8_t nfc_jni_is_ndef; +extern uint8_t *nfc_jni_ndef_buf; +extern uint32_t nfc_jni_ndef_buf_len; + +static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = +{ + 3, + { 0x46, 0x66, 0x6D } +}; + +/* + * Callbacks + */ + +/* P2P - LLCP callbacks */ +static void nfc_jni_llcp_linkStatus_callback(void *pContext, + phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) +{ + phFriNfc_Llcp_sLinkParameters_t sLinkParams; + JNIEnv *e; + NFCSTATUS status; + + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; + + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + /* Update link status */ + g_eLinkStatus = eLinkStatus; + + if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) + { + REENTRANCE_LOCK(); + status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGW("GetRemote Info failded - Status = %02x",status); + } + else + { + ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, + sLinkParams.miu, + sLinkParams.option, + sLinkParams.wks); + device_connected_flag = 1; + } + } + else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) + { + ALOGI("LLCP Link deactivated"); + free(pContextData); + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Reset incoming socket list */ + while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) + { + pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); + LIST_REMOVE(pListenData, entries); + free(pListenData); + } + + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } +} + +static void nfc_jni_checkLlcp_callback(void *context, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; + + LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, + phLibNfc_Handle hIncomingSocket) +{ + phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + + /* Store the connection request */ + pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); + if (pListenData == NULL) + { + ALOGE("Failed to create structure to handle incoming LLCP connection request"); + goto clean_and_return; + } + pListenData->pServerSocket = hServiceSocket; + pListenData->pIncomingSocket = hIncomingSocket; + LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); + + /* Signal pending accept operations that the list is updated */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + +clean_and_return: + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); +} + +void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode) +{ + PHNFC_UNUSED_VARIABLE(pContext); + + TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); + + if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) + { + ALOGW("Frame Rejected - Disconnected"); + } + else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) + { + ALOGD("Socket Disconnected"); + } +} + + +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_discover_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNoOfRemoteDev) +{ + // Always prefer p2p targets over other targets. Otherwise, select the first target + // reported. + uint8_t preferred_index = 0; + for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { + if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { + preferred_index = i; + } + } + return preferred_index; +} + +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status) +{ + JNIEnv *e; + NFCSTATUS ret; + jclass tag_cls = NULL; + jobject target_array; + jobject tag; + jmethodID ctor; + jfieldID f; + const char * typeName; + jbyteArray tagUid; + jbyteArray generalBytes = NULL; + struct nfc_jni_native_data *nat; + struct timespec ts; + phNfc_sData_t data; + int i; + int target_index = 0; // Target that will be reported (if multiple can be >0) + + nat = (struct nfc_jni_native_data *)pContext; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); + + /* Notify manager that a target was deselected */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); + TRACE("Discovered %d tags", uNofRemoteDev); + + target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); + + /* Reset device connected flag */ + device_connected_flag = 1; + phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; + phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + + tag_cls = e->GetObjectClass(nat->cached_P2pDevice); + if(e->ExceptionCheck()) + { + ALOGE("Get Object Class Error"); + kill_client(nat); + return; + } + + /* New target instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID(tag_cls, "mMode", "I"); + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + ALOGD("Discovered P2P Initiator"); + e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); + } + else + { + ALOGD("Discovered P2P Target"); + e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); + } + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + /* Set General Bytes */ + f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes length ="); + for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) + { + ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); + } + + generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + + e->SetByteArrayRegion(generalBytes, 0, + remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, + (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); + + e->SetObjectField(tag, f, generalBytes); + } + + /* Set tag handle */ + f = e->GetFieldID(tag_cls, "mHandle", "I"); + e->SetIntField(tag, f,(jint)remDevHandle); + TRACE("Target handle = 0x%08x",remDevHandle); + } + else + { + tag_cls = e->GetObjectClass(nat->cached_NfcTag); + if(e->ExceptionCheck()) + { + kill_client(nat); + return; + } + + /* New tag instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + bool multi_protocol = false; + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + TRACE("Multiple Protocol TAG detected\n"); + multi_protocol = true; + } + + /* Set tag UID */ + f = e->GetFieldID(tag_cls, "mUid", "[B"); + data = get_target_uid(remDevInfo); + tagUid = e->NewByteArray(data.length); + if(data.length > 0) + { + e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); + } + e->SetObjectField(tag, f, tagUid); + + /* Generate technology list */ + jintArray techList; + jintArray handleList; + jintArray typeList; + nfc_jni_get_technology_tree(e, psRemoteDevList, + multi_protocol ? uNofRemoteDev : 1, + &techList, &handleList, &typeList); + + /* Push the technology list into the java object */ + f = e->GetFieldID(tag_cls, "mTechList", "[I"); + e->SetObjectField(tag, f, techList); + + f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); + e->SetObjectField(tag, f, handleList); + + f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField(tag, f, typeList); + + f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); + e->SetIntField(tag, f,(jint)-1); + + f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); + e->SetIntField(tag, f,(jint)-1); + } + + storedHandle = remDevHandle; + if (nat->tag != NULL) { + e->DeleteGlobalRef(nat->tag); + } + nat->tag = e->NewGlobalRef(tag); + + /* Notify the service */ + TRACE("Notify Nfc Service"); + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + /* Store the hanlde of the P2P device */ + hLlcpHandle = remDevHandle; + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + /* Notify manager that new a tag was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + e->DeleteLocalRef(tag); + } +} + +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_init_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_deinit_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Card Emulation callback */ +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) +{ + JNIEnv *e; + jobject tmp_array = NULL; + jobject mifare_block = NULL; + struct nfc_jni_native_data *nat; + phNfc_sData_t *aid; + phNfc_sData_t *mifare_command; + struct nfc_jni_callback_data *pCallbackData; + int i=0; + + LOG_CALLBACK("nfc_jni_transaction_callback", status); + + nat = (struct nfc_jni_native_data *)context; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_SUCCESS) + { + switch(evt_type) + { + case phLibNfc_eSE_EvtStartTransaction: + { + TRACE("> SE EVT_START_TRANSACTION"); + if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) + { + aid = &(evt_info->UiccEvtInfo.aid); + + ALOGD("> AID DETECTED"); + + if(aid != NULL) + { + if (TRACE_ENABLED == 1) { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + ALOGD("> AID: %s", aid_str); + } + tmp_array = e->NewByteArray(aid->length); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + goto error; + } + + TRACE("Notify Nfc Service"); + /* Notify manager that a new event occurred on a SE */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + ALOGD("> NO AID DETECTED"); + } + }break; + + case phLibNfc_eSE_EvtApduReceived: + { + phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); + TRACE("> SE EVT_APDU_RECEIVED"); + + if (apdu != NULL) { + TRACE(" APDU length=%d", apdu->length); + tmp_array = e->NewByteArray(apdu->length); + if (tmp_array == NULL) { + goto error; + } + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); + if (e->ExceptionCheck()) { + goto error; + } + } else { + TRACE(" APDU EMPTY"); + } + + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); + }break; + + case phLibNfc_eSE_EvtCardRemoval: + { + TRACE("> SE EVT_EMV_CARD_REMOVAL"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); + }break; + + case phLibNfc_eSE_EvtMifareAccess: + { + TRACE("> SE EVT_MIFARE_ACCESS"); + mifare_command = &(evt_info->UiccEvtInfo.aid); + TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); + tmp_array = e->NewByteArray(2); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); + }break; + + case phLibNfc_eSE_EvtFieldOn: + { + TRACE("> SE EVT_FIELD_ON"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); + }break; + + case phLibNfc_eSE_EvtFieldOff: + { + TRACE("> SE EVT_FIELD_OFF"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); + }break; + + default: + { + TRACE("Unknown SE event"); + }break; + } + } + else + { + ALOGE("SE transaction notification error"); + goto error; + } + + /* Function finished, now clean and return */ + goto clean_and_return; + + error: + /* In case of error, just discard the notification */ + ALOGE("Failed to send SE transaction notification"); + e->ExceptionClear(); + + clean_and_return: + if(tmp_array != NULL) + { + e->DeleteLocalRef(tmp_array); + } +} + +static void nfc_jni_se_set_mode_callback(void *pContext, + phLibNfc_Handle handle, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* + * NFCManager methods + */ + +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) +{ + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ + nfc_jni_reset_timeout_values(); + + /* Reload the p2p modes */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Start Polling loop */ + TRACE("****** Start NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, + nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + +static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) +{ + phLibNfc_sADD_Cfg_t discovery_cfg; + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + discovery_cfg.PollDevInfo.PollEnabled = 0; + discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; + discovery_cfg.NfcIP_Target_Mode = 0; + discovery_cfg.NfcIP_Tgt_Disable = TRUE; + + /* Start Polling loop */ + TRACE("****** Stop NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nfc_jni_stop_discovery_locked(nat); + + CONCURRENCY_UNLOCK(); + +} + +static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + nat = nfc_jni_get_nat(e, o); + + /* Register callback for remote device notifications. + * Must re-register every time we turn on discovery, since other operations + * (such as opening the Secure Element) can change the remote device + * notification callback*/ + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", + nat->registry_info.Jewel==TRUE?"J":"", + nat->registry_info.MifareUL==TRUE?"UL":"", + nat->registry_info.MifareStd==TRUE?"Mi":"", + nat->registry_info.Felica==TRUE?"F":"", + nat->registry_info.ISO14443_4A==TRUE?"4A":"", + nat->registry_info.ISO14443_4B==TRUE?"4B":"", + nat->registry_info.NFC==TRUE?"P2P":"", + nat->registry_info.ISO15693==TRUE?"R":"", ret); + + nfc_jni_start_discovery_locked(nat, false); +clean_and_return: + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { + CONCURRENCY_LOCK(); + nfc_jni_reset_timeout_values(); + CONCURRENCY_UNLOCK(); +} + +static void setFelicaTimeout(jint timeout) { + // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. + // It can be set to 0 to disable the timeout altogether, in which case we + // use the sw watchdog as a fallback. + if (timeout <= 255) { + phLibNfc_SetFelicaTimeout(timeout); + } else { + // Disable hw timeout, use sw watchdog for timeout + phLibNfc_SetFelicaTimeout(0); + phLibNfc_SetHciTimeout(timeout); + } + +} +// Calculates ceiling log2 of value +static unsigned int log2(int value) { + unsigned int ret = 0; + bool isPowerOf2 = ((value & (value - 1)) == 0); + while ( (value >> ret) > 1 ) ret++; + if (!isPowerOf2) ret++; + return ret; +} + +// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X +// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X +// +// We keep the constant part of the formula in a static; note the factor +// 1000 off, which is due to the fact that the formula calculates seconds, +// but this method gets milliseconds as an argument. +static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; + +static int calcTimeout(int timeout_in_ms) { + // timeout = (256 * 16 / 13560000) * 2 ^ X + // First find the first X for which timeout > requested timeout + return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); +} + +static void setIsoDepTimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + // Then re-compute the actual timeout based on X + double actual_timeout = nxp_nfc_timeout_factor * (1 << value); + // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, + // but it will take some time to get back through the sw layers. + // 500 ms should be enough). + phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); + value |= 0x10; // bit 4 to enable timeout + phLibNfc_SetIsoXchgTimeout(value); + } + else { + // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout + // must be disabled completely, to prevent the PN544 from aborting + // the transaction. We reuse the HCI sw watchdog to catch the timeout + // in that case. + phLibNfc_SetIsoXchgTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static void setNfcATimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + phLibNfc_SetMifareRawTimeout(value); + } + else { + // Disable mifare raw timeout, use HCI sw watchdog instead + phLibNfc_SetMifareRawTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, + jint tech, jint timeout) { + bool success = false; + CONCURRENCY_LOCK(); + if (timeout <= 0) { + ALOGE("Timeout must be positive."); + return false; + } else { + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + setNfcATimeout(timeout); + success = true; + break; + case TARGET_TYPE_ISO14443_4: + setIsoDepTimeout(timeout); + success = true; + break; + case TARGET_TYPE_FELICA: + setFelicaTimeout(timeout); + success = true; + break; + default: + ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); + success = false; + } + } + CONCURRENCY_UNLOCK(); + return success; +} + +static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, + jint tech) { + int timeout = -1; + CONCURRENCY_LOCK(); + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + timeout = phLibNfc_GetMifareRawTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_ISO14443_4: + timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_FELICA: + timeout = phLibNfc_GetFelicaTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Felica timeout already in ms + } + break; + default: + ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); + break; + } + CONCURRENCY_UNLOCK(); + return timeout; +} + + +static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct nfc_jni_native_data *nat = NULL; + jclass cls; + jobject obj; + jfieldID f; + + TRACE("****** Init Native Structure ******"); + + /* Initialize native structure */ + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if(nat == NULL) + { + ALOGD("malloc of nfc_jni_native_data failed"); + return FALSE; + } + memset(nat, 0, sizeof(*nat)); + e->GetJavaVM(&(nat->vm)); + nat->env_version = e->GetVersion(); + nat->manager = e->NewGlobalRef(o); + + cls = e->GetObjectClass(o); + f = e->GetFieldID(cls, "mNative", "I"); + e->SetIntField(o, f, (jint)nat); + + /* Initialize native cached references */ + cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, + "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, + "notifyTargetDeselected","()V"); + + cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, + "notifySeFieldActivated", "()V"); + + cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, + "notifySeFieldDeactivated", "()V"); + + cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + TRACE("****** Init Native Structure OK ******"); + return TRUE; + +} + +/* Init/Deinit method */ +static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + int init_result = JNI_FALSE; +#ifdef TNFC_EMULATOR_ONLY + char value[PROPERTY_VALUE_MAX]; +#endif + jboolean result; + + CONCURRENCY_LOCK(); + +#ifdef TNFC_EMULATOR_ONLY + if (!property_get("ro.kernel.qemu", value, 0)) + { + ALOGE("NFC Initialization failed: not running in an emulator\n"); + goto clean_and_return; + } +#endif + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nat->seId = SMX_SECURE_ELEMENT_ID; + + nat->lto = 150; // LLCP_LTO + nat->miu = 128; // LLCP_MIU + // WKS indicates well-known services; 1 << sap for each supported SAP. + // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) + nat->wks = 0x13; // LLCP_WKS + nat->opt = 0; // LLCP_OPT + nat->p2p_initiator_modes = phNfc_eP2P_ALL; + nat->p2p_target_modes = 0x0E; // All passive except 106, active + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; + + nat->registry_info.MifareUL = TRUE; + nat->registry_info.MifareStd = TRUE; + nat->registry_info.ISO14443_4A = TRUE; + nat->registry_info.ISO14443_4B = TRUE; + nat->registry_info.Jewel = TRUE; + nat->registry_info.Felica = TRUE; + nat->registry_info.NFC = TRUE; + nat->registry_info.ISO15693 = TRUE; + + exported_nat = nat; + + /* Perform the initialization */ + init_result = nfc_jni_initialize(nat); + +clean_and_return: + CONCURRENCY_UNLOCK(); + + /* Convert the result and return */ + return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; +} + +static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) +{ + struct timespec ts; + NFCSTATUS status; + int result = JNI_FALSE; + struct nfc_jni_native_data *nat; + int bStackReset = FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Clear previous configuration */ + memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); + memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); + + /* Create the local semaphore */ + if (nfc_cb_data_init(&cb_data, NULL)) + { + TRACE("phLibNfc_Mgt_DeInitialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status == NFCSTATUS_PENDING) + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts) == -1) + { + ALOGW("Operation timed out"); + bStackReset = TRUE; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Failed to deinit the stack"); + bStackReset = TRUE; + } + } + else + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + bStackReset = TRUE; + } + nfc_cb_data_deinit(&cb_data); + } + else + { + ALOGE("Failed to create semaphore (errno=0x%08x)", errno); + bStackReset = TRUE; + } + + kill_client(nat); + + if(bStackReset == TRUE) + { + /* Complete deinit. failed, try hard restart of NFC */ + ALOGW("Reseting stack..."); + emergency_recovery(nat); + } + + result = nfc_jni_unconfigure_driver(nat); + + TRACE("NFC Deinitialized"); + + CONCURRENCY_UNLOCK(); + + return TRUE; +} + +/* Secure Element methods */ +static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { + NFCSTATUS ret; + jintArray list= NULL; + phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; + + TRACE("****** Get Secure Element List ******"); + + TRACE("phLibNfc_SE_GetSecureElementList()"); + REENTRANCE_LOCK(); + ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_SUCCESS) { + ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + return list; + } + TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + + TRACE("Nb SE: %d", se_count); + list =e->NewIntArray(se_count); + for (i = 0; i < se_count; i++) { + if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } + e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); + } + + e->DeleteLocalRef(list); + + return list; +} + +static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Select Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Virtual */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING) { + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Deselect Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Default */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, + nfc_jni_se_set_mode_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); + if (ret != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +/* Llcp methods */ + +static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + bool freeData = false; + jboolean result = JNI_FALSE; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data *cb_data; + + + CONCURRENCY_LOCK(); + + /* Memory allocation for cb_data + * This is on the heap because it is used by libnfc + * even after this call has succesfully finished. It is only freed + * upon link closure in nfc_jni_llcp_linkStatus_callback. + */ + cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(cb_data, (void*)nat)) + { + goto clean_and_return; + } + + /* Check LLCP compliancy */ + TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, + nfc_jni_checkLlcp_callback, + nfc_jni_llcp_linkStatus_callback, + (void*)cb_data); + REENTRANCE_UNLOCK(); + /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol + * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + freeData = true; + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data->sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data->status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(cb_data); + if (freeData) { + free(cb_data); + } + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Activate(hLlcpHandle); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_FALSE; + } +} + + + +static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, + jint nSap, jstring sn) +{ + NFCSTATUS ret; + jobject connectionlessSocket = NULL; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_native_data *nat; + phNfc_sData_t sWorkingBuffer = {NULL, 0}; + phNfc_sData_t serviceName = {NULL, 0}; + phLibNfc_Llcp_sLinkParameters_t sParams; + jclass clsNativeConnectionlessSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Allocate Working buffer length */ + phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); + sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, + NULL, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + + /* Create new NativeLlcpConnectionlessSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + { + goto error; + } + + /* Get NativeConnectionless class object */ + clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); + if(e->ExceptionCheck()) + { + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); + e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); + TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); + + /* Set the miu link of the connectionless socket */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); + e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); + TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); + e->SetIntField(connectionlessSocket, f,(jint)nSap); + TRACE("Connectionless socket SAP = %d\n",nSap); + + return connectionlessSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + + if (sWorkingBuffer.buffer != NULL) { + free(sWorkingBuffer.buffer); + } + + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + phNfc_sData_t serviceName; + struct nfc_jni_native_data *nat; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + ret = phLibNfc_Llcp_Close(hLlcpSocket); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Listen( hLlcpSocket, + nfc_jni_llcp_transport_listen_socket_callback, + (void*)hLlcpSocket); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + /* Close created socket */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpServiceSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + { + ALOGE("Llcp Socket object creation error"); + goto error; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); + if(e->ExceptionCheck()) + { + ALOGE("Llcp Socket get object class error"); + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); + TRACE("Service socket Handle = %02x\n",hLlcpSocket); + + /* Set socket linear buffer length */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField(serviceSocket, f,(jint)linearBufferLength); + TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField(serviceSocket, f,(jint)miu); + TRACE("Service socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField(serviceSocket, f,(jint)rw); + TRACE("Service socket RW = %d\n",rw); + + return serviceSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + struct nfc_jni_native_data *nat; + jclass clsNativeLlcpSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + return NULL; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGE("Llcp socket object creation error"); + return NULL; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGE("Get class object error"); + return NULL; + } + + /* Test if an SAP number is present */ + if(nSap != 0) + { + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + return NULL; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField(clientSocket, f,(jint)nSap); + TRACE("socket SAP = %d\n",nSap); + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hLlcpSocket); + TRACE("socket Handle = %02x\n",hLlcpSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + TRACE("socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + TRACE("socket RW = %d\n",rw); + + + return clientSocket; +} + +static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) +{ + TRACE("Last Error Status = 0x%02x",lastErrorStatus); + + if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) + { + return ERROR_BUFFER_TOO_SMALL; + } + else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) + { + return ERROR_INSUFFICIENT_RESOURCES; + } + else + { + return lastErrorStatus; + } +} + +static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) +{ + emergency_recovery(NULL); +} + +static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting init modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_initiator_modes = modes; +} + +static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting target modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_target_modes = modes; +} + +static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { + bool result = FALSE; + int load_result; + bool wasDisabled = FALSE; + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + NFCSTATUS status = NFCSTATUS_FAILED; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + result = FALSE; + goto clean_and_return; + } + + if (takeLock) + { + CONCURRENCY_LOCK(); + } + + /* Initialize Driver */ + if(!driverConfigured) + { + result = nfc_jni_configure_driver(nat); + wasDisabled = TRUE; + } + TRACE("com_android_nfc_NfcManager_doDownload()"); + + TRACE("Go in Download Mode"); + phLibNfc_Download_Mode(); + + TRACE("Load new Firmware Image"); + load_result = phLibNfc_Load_Firmware_Image(); + if(load_result != 0) + { + TRACE("Load new Firmware Image - status = %d",load_result); + result = FALSE; + goto clean_and_return; + } + + // Download + gInputParam.buffer = InputBuffer; + gInputParam.length = 0x01; + gOutputParam.buffer = OutputBuffer; + gOutputParam.length = 0x01; + + ALOGD("Download new Firmware"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + result = FALSE; + goto clean_and_return; + } + + /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we + try to download an old-style firmware on top of a new-style + firmware. Hence, this is expected behavior, and not an + error condition. */ + if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); + } + + /*Download is successful*/ + result = TRUE; +clean_and_return: + TRACE("phLibNfc_HW_Reset()"); + phLibNfc_HW_Reset(); + /* Deinitialize Driver */ + if(wasDisabled) + { + result = nfc_jni_unconfigure_driver(nat); + } + if (takeLock) + { + CONCURRENCY_UNLOCK(); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + return performDownload(nat, true); +} + +static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); + return e->NewStringUTF(buffer); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)com_android_nfc_NfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void *)com_android_nfc_NfcManager_init_native_struc}, + + {"doInitialize", "()Z", + (void *)com_android_nfc_NfcManager_initialize}, + + {"doDeinitialize", "()Z", + (void *)com_android_nfc_NfcManager_deinitialize}, + + {"enableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)com_android_nfc_NfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)com_android_nfc_NfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)com_android_nfc_NfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)com_android_nfc_NfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)com_android_nfc_NfcManager_doAbort}, + + {"doSetP2pInitiatorModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)com_android_nfc_NfcManager_doDump}, +}; + + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e) +{ + nfc_jni_native_monitor_t *nfc_jni_native_monitor; + + nfc_jni_native_monitor = nfc_jni_init_monitor(); + if(nfc_jni_native_monitor == NULL) + { + ALOGE("NFC Manager cannot recover native monitor %x\n", errno); + return -1; + } + + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; iRemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;iNewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..f969627 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eddde94 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 602b25d..3e7a6b5 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.nxp.NativeNfcManager; -import com.android.nfc.nxp.NativeNfcSecureElement; +import com.android.nfc.dhimpl.NativeNfcManager; +import com.android.nfc.dhimpl.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; diff --git a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index c9d3b5d..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java deleted file mode 100755 index 531afd8..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java deleted file mode 100755 index a337d35..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java deleted file mode 100755 index 4bd8c24..0000000 --- a/src/com/android/nfc/nxp/NativeNfcManager.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java deleted file mode 100755 index 88f9b9d..0000000 --- a/src/com/android/nfc/nxp/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java deleted file mode 100755 index 8996dfb..0000000 --- a/src/com/android/nfc/nxp/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java deleted file mode 100755 index 7c7db41..0000000 --- a/src/com/android/nfc/nxp/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} -- cgit v1.1 From ff94ceff4c2715134c85a84c75d47a5835f1a598 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 24 Jul 2012 20:54:28 -0700 Subject: Revert "Move NXP JNI and DeviceHost implementation into separate dir." This reverts commit 26f6049196acaa9768ba6bdef343216ea878a4c1. --- Android.mk | 8 - jni/Android.mk | 35 + jni/com_android_nfc.cpp | 564 +++++ jni/com_android_nfc.h | 261 ++ ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 ++ jni/com_android_nfc_NativeLlcpServiceSocket.cpp | 227 ++ jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ++++ jni/com_android_nfc_NativeNfcManager.cpp | 2623 ++++++++++++++++++++ jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ++++++ jni/com_android_nfc_NativeNfcTag.cpp | 1255 ++++++++++ jni/com_android_nfc_NativeP2pDevice.cpp | 490 ++++ jni/com_android_nfc_list.cpp | 210 ++ jni/com_android_nfc_list.h | 49 + nxp/jni/Android.mk | 35 - nxp/jni/com_android_nfc.cpp | 564 ----- nxp/jni/com_android_nfc.h | 261 -- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 -- .../com_android_nfc_NativeLlcpServiceSocket.cpp | 227 -- nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ---- nxp/jni/com_android_nfc_NativeNfcManager.cpp | 2623 -------------------- nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ------ nxp/jni/com_android_nfc_NativeNfcTag.cpp | 1255 ---------- nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 490 ---- nxp/jni/com_android_nfc_list.cpp | 210 -- nxp/jni/com_android_nfc_list.h | 49 - .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 - .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 - .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 - .../com/android/nfc/dhimpl/NativeNfcManager.java | 373 --- .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 - nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 803 ------ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 - src/com/android/nfc/NfcService.java | 4 +- .../nfc/nxp/NativeLlcpConnectionlessSocket.java | 78 + .../android/nfc/nxp/NativeLlcpServiceSocket.java | 53 + src/com/android/nfc/nxp/NativeLlcpSocket.java | 99 + src/com/android/nfc/nxp/NativeNfcManager.java | 373 +++ .../android/nfc/nxp/NativeNfcSecureElement.java | 67 + src/com/android/nfc/nxp/NativeNfcTag.java | 803 ++++++ src/com/android/nfc/nxp/NativeP2pDevice.java | 77 + 40 files changed, 8757 insertions(+), 8765 deletions(-) create mode 100644 jni/Android.mk create mode 100644 jni/com_android_nfc.cpp create mode 100644 jni/com_android_nfc.h create mode 100644 jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp create mode 100644 jni/com_android_nfc_NativeLlcpServiceSocket.cpp create mode 100644 jni/com_android_nfc_NativeLlcpSocket.cpp create mode 100644 jni/com_android_nfc_NativeNfcManager.cpp create mode 100755 jni/com_android_nfc_NativeNfcSecureElement.cpp create mode 100644 jni/com_android_nfc_NativeNfcTag.cpp create mode 100644 jni/com_android_nfc_NativeP2pDevice.cpp create mode 100644 jni/com_android_nfc_list.cpp create mode 100644 jni/com_android_nfc_list.h delete mode 100644 nxp/jni/Android.mk delete mode 100644 nxp/jni/com_android_nfc.cpp delete mode 100644 nxp/jni/com_android_nfc.h delete mode 100644 nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeLlcpSocket.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeNfcManager.cpp delete mode 100755 nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeNfcTag.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeP2pDevice.cpp delete mode 100644 nxp/jni/com_android_nfc_list.cpp delete mode 100644 nxp/jni/com_android_nfc_list.h delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java create mode 100755 src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java create mode 100755 src/com/android/nfc/nxp/NativeLlcpServiceSocket.java create mode 100755 src/com/android/nfc/nxp/NativeLlcpSocket.java create mode 100755 src/com/android/nfc/nxp/NativeNfcManager.java create mode 100755 src/com/android/nfc/nxp/NativeNfcSecureElement.java create mode 100755 src/com/android/nfc/nxp/NativeNfcTag.java create mode 100755 src/com/android/nfc/nxp/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index 2cdfc68..a041854 100644 --- a/Android.mk +++ b/Android.mk @@ -6,14 +6,6 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) -ifeq ($(NFC_USE_NCI_STACK), true) - LOCAL_SRC_FILES += \ - $(call all-java-files-under, nci) -else - LOCAL_SRC_FILES += \ - $(call all-java-files-under, nxp) -endif - LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h new file mode 100644 index 0000000..b876dad --- /dev/null +++ b/jni/com_android_nfc.h @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include +#include + +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) + #define TRACE_ENABLED 1 +#else + #define LOG_CALLBACK(...) + #define TRACE(...) + #define TRACE_ENABLED 0 +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeLlcpSocket.cpp b/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..e6da0fa --- /dev/null +++ b/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2623 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "com_android_nfc.h" + +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +extern uint32_t libnfc_llc_error_count; + +static phLibNfc_sConfig_t gDrvCfg; +void *gHWRef; +static phNfc_sData_t gInputParam; +static phNfc_sData_t gOutputParam; + +uint8_t device_connected_flag; +static bool driverConfigured = FALSE; + +static phLibNfc_Handle hLlcpHandle; +static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; +static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; + +static jmethodID cached_NfcManager_notifyNdefMessageListeners; +static jmethodID cached_NfcManager_notifyTransactionListeners; +static jmethodID cached_NfcManager_notifyLlcpLinkActivation; +static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; +static jmethodID cached_NfcManager_notifyTargetDeselected; + +static jmethodID cached_NfcManager_notifySeFieldActivated; +static jmethodID cached_NfcManager_notifySeFieldDeactivated; + +static jmethodID cached_NfcManager_notifySeApduReceived; +static jmethodID cached_NfcManager_notifySeMifareAccess; +static jmethodID cached_NfcManager_notifySeEmvCardRemoval; + +namespace android { + +phLibNfc_Handle storedHandle = 0; + +struct nfc_jni_native_data *exported_nat = NULL; + +/* Internal functions declaration */ +static void *nfc_jni_client_thread(void *arg); +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_se_set_mode_callback(void *context, + phLibNfc_Handle handle, NFCSTATUS status); +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status); +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); +static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); + +/* + * Deferred callback called when client thread must be exited + */ +static void client_kill_deferred_call(void* arg) +{ + struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; + + nat->running = FALSE; +} + +static void kill_client(nfc_jni_native_data *nat) +{ + phDal4Nfc_Message_Wrapper_t wrapper; + phLibNfc_DeferredCall_t *pMsg; + + usleep(50000); + + ALOGD("Terminating client thread..."); + + pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); + pMsg->pCallback = client_kill_deferred_call; + pMsg->pParameter = (void*)nat; + + wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + wrapper.msg.pMsgData = pMsg; + wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); + + phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); +} + +static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_ioctl_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_deinit_download_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) +{ + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + struct timespec ts; + NFCSTATUS status = NFCSTATUS_FAILED; + phLibNfc_StackCapabilities_t caps; + struct nfc_jni_callback_data cb_data; + bool result; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + if(update) + { + //deinit + TRACE("phLibNfc_Mgt_DeInitialize() (download)"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts)) + { + ALOGW("Deinitialization timed out (download)"); + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("Deinitialization FAILED (download)"); + } + TRACE("Deinitialization SUCCESS (download)"); + } + + result = performDownload(nat, false); + + if (!result) { + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + status = cb_data.status; + goto clean_and_return; + } + + /* ====== CAPABILITIES ======= */ + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /*Download is successful*/ + status = NFCSTATUS_SUCCESS; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return status; +} + +static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) +{ + char value[PROPERTY_VALUE_MAX]; + int result = FALSE; + NFCSTATUS status; + + /* ====== CONFIGURE DRIVER ======= */ + /* Configure hardware link */ + gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); + + TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); + REENTRANCE_UNLOCK(); + if(status == NFCSTATUS_ALREADY_INITIALISED) { + ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) + { + ALOGE("pthread_create failed"); + goto clean_and_return; + } + + driverConfigured = TRUE; + +clean_and_return: + return result; +} + +static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) +{ + int result = FALSE; + NFCSTATUS status; + + /* Unconfigure driver */ + TRACE("phLibNfc_Mgt_UnConfigureDriver()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); + } + else + { + ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = TRUE; + } + + driverConfigured = FALSE; + + return result; +} + +/* Initialization function */ +static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { + struct timespec ts; + uint8_t resp[16]; + NFCSTATUS status; + phLibNfc_StackCapabilities_t caps; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; + phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; + struct nfc_jni_callback_data cb_data; + uint8_t firmware_status; + uint8_t update = TRUE; + int result = JNI_FALSE; + const hw_module_t* hw_module; + nfc_pn544_device_t* pn544_dev = NULL; + int ret = 0; + ALOGD("Start Initialization\n"); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Get EEPROM values and device port from product-specific settings */ + ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); + if (ret) { + ALOGE("hw_get_module() failed."); + goto clean_and_return; + } + ret = nfc_pn544_open(hw_module, &pn544_dev); + if (ret) { + ALOGE("Could not open pn544 hw_module."); + goto clean_and_return; + } + if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { + ALOGE("Could not load EEPROM settings"); + goto clean_and_return; + } + + /* Reset device connected handle */ + device_connected_flag = 0; + + /* Reset stored handle */ + storedHandle = 0; + + /* Initialize Driver */ + if(!driverConfigured) + { + nfc_jni_configure_driver(nat); + } + + /* ====== INITIALIZE ======= */ + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + update = FALSE; + goto force_download; + } + TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + update = FALSE; + goto force_download; + } + + /* ====== CAPABILITIES ======= */ + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /* ====== FIRMWARE VERSION ======= */ + if(caps.psDevCapabilities.firmware_update_info) + { +force_download: + for (i=0; i<3; i++) + { + TRACE("Firmware version not UpToDate"); + status = nfc_jni_download_locked(nat, update); + if(status == NFCSTATUS_SUCCESS) + { + ALOGI("Firmware update SUCCESS"); + break; + } + ALOGW("Firmware update FAILED"); + update = FALSE; + } + if(i>=3) + { + ALOGE("Unable to update firmware, giving up"); + goto clean_and_return; + } + } + else + { + TRACE("Firmware version UpToDate"); + } + /* ====== EEPROM SETTINGS ======= */ + + // Update EEPROM settings + TRACE("****** START EEPROM SETTINGS UPDATE ******"); + for (i = 0; i < pn544_dev->num_eeprom_settings; i++) + { + char eeprom_property[PROPERTY_KEY_MAX]; + char eeprom_value[PROPERTY_VALUE_MAX]; + uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); + TRACE("> EEPROM SETTING: %d", i); + + // Check for override of this EEPROM value in properties + snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", + eeprom_base[1], eeprom_base[2]); + TRACE(">> Checking property: %s", eeprom_property); + if (property_get(eeprom_property, eeprom_value, "") == 2) { + int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); + ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", + eeprom_base[1], eeprom_base[2], eeprom_value_num); + eeprom_base[3] = eeprom_value_num; + } + + TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], + eeprom_base[3]); + gInputParam.buffer = eeprom_base; + gInputParam.length = 0x04; + gOutputParam.buffer = resp; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if (cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + } + TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); + + /* ====== SECURE ELEMENTS ======= */ + + REENTRANCE_LOCK(); + ALOGD("phLibNfc_SE_GetSecureElementList()"); + status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + + ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i < No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); + } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); + } + + /* Set SE mode - Off */ + REENTRANCE_LOCK(); + status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, + phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + } + + /* ====== LLCP ======= */ + + /* LLCP Params */ + TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); + LlcpConfigInfo.miu = nat->miu; + LlcpConfigInfo.lto = nat->lto; + LlcpConfigInfo.wks = nat->wks; + LlcpConfigInfo.option = nat->opt; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, + nfc_jni_llcpcfg_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* ===== DISCOVERY ==== */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.Duration = 300000; /* in ms */ + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== END ======= */ + + ALOGI("NFC Initialized"); + + result = TRUE; + +clean_and_return: + if (result != TRUE) + { + if(nat) + { + kill_client(nat); + } + } + if (pn544_dev != NULL) { + nfc_pn544_close(pn544_dev); + } + nfc_cb_data_deinit(&cb_data); + + return result; +} + +static int is_user_build() { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", value, ""); + return !strncmp("user", value, PROPERTY_VALUE_MAX); +} + +/* + * Last-chance fallback when there is no clean way to recover + * Performs a software reset + */ +void emergency_recovery(struct nfc_jni_native_data *nat) { + if (!is_user_build()) { + ALOGE("emergency_recovery: force restart of NFC service"); + } else { + // dont recover immediately, so we can debug + unsigned int t; + for (t=1; t < 1000000; t <<= 1) { + ALOGE("emergency_recovery: NFC stack dead-locked"); + sleep(t); + } + } + phLibNfc_Mgt_Recovery(); + abort(); // force a noisy crash +} + +void nfc_jni_reset_timeout_values() +{ + REENTRANCE_LOCK(); + phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); + phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); + phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); + phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); + REENTRANCE_UNLOCK(); +} + +/* + * Restart the polling loop when unable to perform disconnect + */ +void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) +{ + nfc_jni_start_discovery_locked(nat, true); +} + + /* + * Utility to recover UID from target infos + */ +static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + phNfc_sData_t uid; + + switch(psRemoteDevInfo->RemDevType) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_3A_PICC: + case phNfc_eMifare_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; + break; + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; + uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); + break; + case phNfc_eFelica_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; + uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; + break; + case phNfc_eJewel_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; + break; + case phNfc_eISO15693_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; + break; + case phNfc_eNfcIP1_Target: + case phNfc_eNfcIP1_Initiator: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; + uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; + break; + default: + uid.buffer = NULL; + uid.length = 0; + break; + } + + return uid; +} + +/* + * NFC stack message processing + */ +static void *nfc_jni_client_thread(void *arg) +{ + struct nfc_jni_native_data *nat; + JNIEnv *e; + JavaVMAttachArgs thread_args; + phDal4Nfc_Message_Wrapper_t wrapper; + + nat = (struct nfc_jni_native_data *)arg; + + thread_args.name = "NFC Message Loop"; + thread_args.version = nat->env_version; + thread_args.group = NULL; + + nat->vm->AttachCurrentThread(&e, &thread_args); + pthread_setname_np(pthread_self(), "message"); + + TRACE("NFC client started"); + nat->running = TRUE; + while(nat->running == TRUE) + { + /* Fetch next message from the NFC stack message queue */ + if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, + sizeof(phLibNfc_Message_t), 0, 0) == -1) + { + ALOGE("NFC client received bad message"); + continue; + } + + switch(wrapper.msg.eMsgType) + { + case PH_LIBNFC_DEFERREDCALL_MSG: + { + phLibNfc_DeferredCall_t *msg = + (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); + + REENTRANCE_LOCK(); + msg->pCallback(msg->pParameter); + REENTRANCE_UNLOCK(); + + break; + } + } + } + TRACE("NFC client stopped"); + + nat->vm->DetachCurrentThread(); + + return NULL; +} + +extern uint8_t nfc_jni_is_ndef; +extern uint8_t *nfc_jni_ndef_buf; +extern uint32_t nfc_jni_ndef_buf_len; + +static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = +{ + 3, + { 0x46, 0x66, 0x6D } +}; + +/* + * Callbacks + */ + +/* P2P - LLCP callbacks */ +static void nfc_jni_llcp_linkStatus_callback(void *pContext, + phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) +{ + phFriNfc_Llcp_sLinkParameters_t sLinkParams; + JNIEnv *e; + NFCSTATUS status; + + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; + + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + /* Update link status */ + g_eLinkStatus = eLinkStatus; + + if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) + { + REENTRANCE_LOCK(); + status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGW("GetRemote Info failded - Status = %02x",status); + } + else + { + ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, + sLinkParams.miu, + sLinkParams.option, + sLinkParams.wks); + device_connected_flag = 1; + } + } + else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) + { + ALOGI("LLCP Link deactivated"); + free(pContextData); + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Reset incoming socket list */ + while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) + { + pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); + LIST_REMOVE(pListenData, entries); + free(pListenData); + } + + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } +} + +static void nfc_jni_checkLlcp_callback(void *context, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; + + LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, + phLibNfc_Handle hIncomingSocket) +{ + phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + + /* Store the connection request */ + pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); + if (pListenData == NULL) + { + ALOGE("Failed to create structure to handle incoming LLCP connection request"); + goto clean_and_return; + } + pListenData->pServerSocket = hServiceSocket; + pListenData->pIncomingSocket = hIncomingSocket; + LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); + + /* Signal pending accept operations that the list is updated */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + +clean_and_return: + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); +} + +void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode) +{ + PHNFC_UNUSED_VARIABLE(pContext); + + TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); + + if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) + { + ALOGW("Frame Rejected - Disconnected"); + } + else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) + { + ALOGD("Socket Disconnected"); + } +} + + +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_discover_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNoOfRemoteDev) +{ + // Always prefer p2p targets over other targets. Otherwise, select the first target + // reported. + uint8_t preferred_index = 0; + for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { + if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { + preferred_index = i; + } + } + return preferred_index; +} + +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status) +{ + JNIEnv *e; + NFCSTATUS ret; + jclass tag_cls = NULL; + jobject target_array; + jobject tag; + jmethodID ctor; + jfieldID f; + const char * typeName; + jbyteArray tagUid; + jbyteArray generalBytes = NULL; + struct nfc_jni_native_data *nat; + struct timespec ts; + phNfc_sData_t data; + int i; + int target_index = 0; // Target that will be reported (if multiple can be >0) + + nat = (struct nfc_jni_native_data *)pContext; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); + + /* Notify manager that a target was deselected */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); + TRACE("Discovered %d tags", uNofRemoteDev); + + target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); + + /* Reset device connected flag */ + device_connected_flag = 1; + phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; + phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + + tag_cls = e->GetObjectClass(nat->cached_P2pDevice); + if(e->ExceptionCheck()) + { + ALOGE("Get Object Class Error"); + kill_client(nat); + return; + } + + /* New target instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID(tag_cls, "mMode", "I"); + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + ALOGD("Discovered P2P Initiator"); + e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); + } + else + { + ALOGD("Discovered P2P Target"); + e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); + } + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + /* Set General Bytes */ + f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes length ="); + for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) + { + ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); + } + + generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + + e->SetByteArrayRegion(generalBytes, 0, + remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, + (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); + + e->SetObjectField(tag, f, generalBytes); + } + + /* Set tag handle */ + f = e->GetFieldID(tag_cls, "mHandle", "I"); + e->SetIntField(tag, f,(jint)remDevHandle); + TRACE("Target handle = 0x%08x",remDevHandle); + } + else + { + tag_cls = e->GetObjectClass(nat->cached_NfcTag); + if(e->ExceptionCheck()) + { + kill_client(nat); + return; + } + + /* New tag instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + bool multi_protocol = false; + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + TRACE("Multiple Protocol TAG detected\n"); + multi_protocol = true; + } + + /* Set tag UID */ + f = e->GetFieldID(tag_cls, "mUid", "[B"); + data = get_target_uid(remDevInfo); + tagUid = e->NewByteArray(data.length); + if(data.length > 0) + { + e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); + } + e->SetObjectField(tag, f, tagUid); + + /* Generate technology list */ + jintArray techList; + jintArray handleList; + jintArray typeList; + nfc_jni_get_technology_tree(e, psRemoteDevList, + multi_protocol ? uNofRemoteDev : 1, + &techList, &handleList, &typeList); + + /* Push the technology list into the java object */ + f = e->GetFieldID(tag_cls, "mTechList", "[I"); + e->SetObjectField(tag, f, techList); + + f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); + e->SetObjectField(tag, f, handleList); + + f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField(tag, f, typeList); + + f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); + e->SetIntField(tag, f,(jint)-1); + + f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); + e->SetIntField(tag, f,(jint)-1); + } + + storedHandle = remDevHandle; + if (nat->tag != NULL) { + e->DeleteGlobalRef(nat->tag); + } + nat->tag = e->NewGlobalRef(tag); + + /* Notify the service */ + TRACE("Notify Nfc Service"); + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + /* Store the hanlde of the P2P device */ + hLlcpHandle = remDevHandle; + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + /* Notify manager that new a tag was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + e->DeleteLocalRef(tag); + } +} + +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_init_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_deinit_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Card Emulation callback */ +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) +{ + JNIEnv *e; + jobject tmp_array = NULL; + jobject mifare_block = NULL; + struct nfc_jni_native_data *nat; + phNfc_sData_t *aid; + phNfc_sData_t *mifare_command; + struct nfc_jni_callback_data *pCallbackData; + int i=0; + + LOG_CALLBACK("nfc_jni_transaction_callback", status); + + nat = (struct nfc_jni_native_data *)context; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_SUCCESS) + { + switch(evt_type) + { + case phLibNfc_eSE_EvtStartTransaction: + { + TRACE("> SE EVT_START_TRANSACTION"); + if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) + { + aid = &(evt_info->UiccEvtInfo.aid); + + ALOGD("> AID DETECTED"); + + if(aid != NULL) + { + if (TRACE_ENABLED == 1) { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + ALOGD("> AID: %s", aid_str); + } + tmp_array = e->NewByteArray(aid->length); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + goto error; + } + + TRACE("Notify Nfc Service"); + /* Notify manager that a new event occurred on a SE */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + ALOGD("> NO AID DETECTED"); + } + }break; + + case phLibNfc_eSE_EvtApduReceived: + { + phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); + TRACE("> SE EVT_APDU_RECEIVED"); + + if (apdu != NULL) { + TRACE(" APDU length=%d", apdu->length); + tmp_array = e->NewByteArray(apdu->length); + if (tmp_array == NULL) { + goto error; + } + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); + if (e->ExceptionCheck()) { + goto error; + } + } else { + TRACE(" APDU EMPTY"); + } + + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); + }break; + + case phLibNfc_eSE_EvtCardRemoval: + { + TRACE("> SE EVT_EMV_CARD_REMOVAL"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); + }break; + + case phLibNfc_eSE_EvtMifareAccess: + { + TRACE("> SE EVT_MIFARE_ACCESS"); + mifare_command = &(evt_info->UiccEvtInfo.aid); + TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); + tmp_array = e->NewByteArray(2); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); + }break; + + case phLibNfc_eSE_EvtFieldOn: + { + TRACE("> SE EVT_FIELD_ON"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); + }break; + + case phLibNfc_eSE_EvtFieldOff: + { + TRACE("> SE EVT_FIELD_OFF"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); + }break; + + default: + { + TRACE("Unknown SE event"); + }break; + } + } + else + { + ALOGE("SE transaction notification error"); + goto error; + } + + /* Function finished, now clean and return */ + goto clean_and_return; + + error: + /* In case of error, just discard the notification */ + ALOGE("Failed to send SE transaction notification"); + e->ExceptionClear(); + + clean_and_return: + if(tmp_array != NULL) + { + e->DeleteLocalRef(tmp_array); + } +} + +static void nfc_jni_se_set_mode_callback(void *pContext, + phLibNfc_Handle handle, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* + * NFCManager methods + */ + +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) +{ + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ + nfc_jni_reset_timeout_values(); + + /* Reload the p2p modes */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Start Polling loop */ + TRACE("****** Start NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, + nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + +static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) +{ + phLibNfc_sADD_Cfg_t discovery_cfg; + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + discovery_cfg.PollDevInfo.PollEnabled = 0; + discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; + discovery_cfg.NfcIP_Target_Mode = 0; + discovery_cfg.NfcIP_Tgt_Disable = TRUE; + + /* Start Polling loop */ + TRACE("****** Stop NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nfc_jni_stop_discovery_locked(nat); + + CONCURRENCY_UNLOCK(); + +} + +static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + nat = nfc_jni_get_nat(e, o); + + /* Register callback for remote device notifications. + * Must re-register every time we turn on discovery, since other operations + * (such as opening the Secure Element) can change the remote device + * notification callback*/ + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", + nat->registry_info.Jewel==TRUE?"J":"", + nat->registry_info.MifareUL==TRUE?"UL":"", + nat->registry_info.MifareStd==TRUE?"Mi":"", + nat->registry_info.Felica==TRUE?"F":"", + nat->registry_info.ISO14443_4A==TRUE?"4A":"", + nat->registry_info.ISO14443_4B==TRUE?"4B":"", + nat->registry_info.NFC==TRUE?"P2P":"", + nat->registry_info.ISO15693==TRUE?"R":"", ret); + + nfc_jni_start_discovery_locked(nat, false); +clean_and_return: + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { + CONCURRENCY_LOCK(); + nfc_jni_reset_timeout_values(); + CONCURRENCY_UNLOCK(); +} + +static void setFelicaTimeout(jint timeout) { + // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. + // It can be set to 0 to disable the timeout altogether, in which case we + // use the sw watchdog as a fallback. + if (timeout <= 255) { + phLibNfc_SetFelicaTimeout(timeout); + } else { + // Disable hw timeout, use sw watchdog for timeout + phLibNfc_SetFelicaTimeout(0); + phLibNfc_SetHciTimeout(timeout); + } + +} +// Calculates ceiling log2 of value +static unsigned int log2(int value) { + unsigned int ret = 0; + bool isPowerOf2 = ((value & (value - 1)) == 0); + while ( (value >> ret) > 1 ) ret++; + if (!isPowerOf2) ret++; + return ret; +} + +// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X +// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X +// +// We keep the constant part of the formula in a static; note the factor +// 1000 off, which is due to the fact that the formula calculates seconds, +// but this method gets milliseconds as an argument. +static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; + +static int calcTimeout(int timeout_in_ms) { + // timeout = (256 * 16 / 13560000) * 2 ^ X + // First find the first X for which timeout > requested timeout + return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); +} + +static void setIsoDepTimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + // Then re-compute the actual timeout based on X + double actual_timeout = nxp_nfc_timeout_factor * (1 << value); + // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, + // but it will take some time to get back through the sw layers. + // 500 ms should be enough). + phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); + value |= 0x10; // bit 4 to enable timeout + phLibNfc_SetIsoXchgTimeout(value); + } + else { + // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout + // must be disabled completely, to prevent the PN544 from aborting + // the transaction. We reuse the HCI sw watchdog to catch the timeout + // in that case. + phLibNfc_SetIsoXchgTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static void setNfcATimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + phLibNfc_SetMifareRawTimeout(value); + } + else { + // Disable mifare raw timeout, use HCI sw watchdog instead + phLibNfc_SetMifareRawTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, + jint tech, jint timeout) { + bool success = false; + CONCURRENCY_LOCK(); + if (timeout <= 0) { + ALOGE("Timeout must be positive."); + return false; + } else { + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + setNfcATimeout(timeout); + success = true; + break; + case TARGET_TYPE_ISO14443_4: + setIsoDepTimeout(timeout); + success = true; + break; + case TARGET_TYPE_FELICA: + setFelicaTimeout(timeout); + success = true; + break; + default: + ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); + success = false; + } + } + CONCURRENCY_UNLOCK(); + return success; +} + +static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, + jint tech) { + int timeout = -1; + CONCURRENCY_LOCK(); + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + timeout = phLibNfc_GetMifareRawTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_ISO14443_4: + timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_FELICA: + timeout = phLibNfc_GetFelicaTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Felica timeout already in ms + } + break; + default: + ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); + break; + } + CONCURRENCY_UNLOCK(); + return timeout; +} + + +static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct nfc_jni_native_data *nat = NULL; + jclass cls; + jobject obj; + jfieldID f; + + TRACE("****** Init Native Structure ******"); + + /* Initialize native structure */ + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if(nat == NULL) + { + ALOGD("malloc of nfc_jni_native_data failed"); + return FALSE; + } + memset(nat, 0, sizeof(*nat)); + e->GetJavaVM(&(nat->vm)); + nat->env_version = e->GetVersion(); + nat->manager = e->NewGlobalRef(o); + + cls = e->GetObjectClass(o); + f = e->GetFieldID(cls, "mNative", "I"); + e->SetIntField(o, f, (jint)nat); + + /* Initialize native cached references */ + cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, + "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, + "notifyTargetDeselected","()V"); + + cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, + "notifySeFieldActivated", "()V"); + + cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, + "notifySeFieldDeactivated", "()V"); + + cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + TRACE("****** Init Native Structure OK ******"); + return TRUE; + +} + +/* Init/Deinit method */ +static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + int init_result = JNI_FALSE; +#ifdef TNFC_EMULATOR_ONLY + char value[PROPERTY_VALUE_MAX]; +#endif + jboolean result; + + CONCURRENCY_LOCK(); + +#ifdef TNFC_EMULATOR_ONLY + if (!property_get("ro.kernel.qemu", value, 0)) + { + ALOGE("NFC Initialization failed: not running in an emulator\n"); + goto clean_and_return; + } +#endif + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nat->seId = SMX_SECURE_ELEMENT_ID; + + nat->lto = 150; // LLCP_LTO + nat->miu = 128; // LLCP_MIU + // WKS indicates well-known services; 1 << sap for each supported SAP. + // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) + nat->wks = 0x13; // LLCP_WKS + nat->opt = 0; // LLCP_OPT + nat->p2p_initiator_modes = phNfc_eP2P_ALL; + nat->p2p_target_modes = 0x0E; // All passive except 106, active + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; + + nat->registry_info.MifareUL = TRUE; + nat->registry_info.MifareStd = TRUE; + nat->registry_info.ISO14443_4A = TRUE; + nat->registry_info.ISO14443_4B = TRUE; + nat->registry_info.Jewel = TRUE; + nat->registry_info.Felica = TRUE; + nat->registry_info.NFC = TRUE; + nat->registry_info.ISO15693 = TRUE; + + exported_nat = nat; + + /* Perform the initialization */ + init_result = nfc_jni_initialize(nat); + +clean_and_return: + CONCURRENCY_UNLOCK(); + + /* Convert the result and return */ + return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; +} + +static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) +{ + struct timespec ts; + NFCSTATUS status; + int result = JNI_FALSE; + struct nfc_jni_native_data *nat; + int bStackReset = FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Clear previous configuration */ + memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); + memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); + + /* Create the local semaphore */ + if (nfc_cb_data_init(&cb_data, NULL)) + { + TRACE("phLibNfc_Mgt_DeInitialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status == NFCSTATUS_PENDING) + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts) == -1) + { + ALOGW("Operation timed out"); + bStackReset = TRUE; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Failed to deinit the stack"); + bStackReset = TRUE; + } + } + else + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + bStackReset = TRUE; + } + nfc_cb_data_deinit(&cb_data); + } + else + { + ALOGE("Failed to create semaphore (errno=0x%08x)", errno); + bStackReset = TRUE; + } + + kill_client(nat); + + if(bStackReset == TRUE) + { + /* Complete deinit. failed, try hard restart of NFC */ + ALOGW("Reseting stack..."); + emergency_recovery(nat); + } + + result = nfc_jni_unconfigure_driver(nat); + + TRACE("NFC Deinitialized"); + + CONCURRENCY_UNLOCK(); + + return TRUE; +} + +/* Secure Element methods */ +static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { + NFCSTATUS ret; + jintArray list= NULL; + phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; + + TRACE("****** Get Secure Element List ******"); + + TRACE("phLibNfc_SE_GetSecureElementList()"); + REENTRANCE_LOCK(); + ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_SUCCESS) { + ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + return list; + } + TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + + TRACE("Nb SE: %d", se_count); + list =e->NewIntArray(se_count); + for (i = 0; i < se_count; i++) { + if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } + e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); + } + + e->DeleteLocalRef(list); + + return list; +} + +static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Select Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Virtual */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING) { + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Deselect Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Default */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, + nfc_jni_se_set_mode_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); + if (ret != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +/* Llcp methods */ + +static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + bool freeData = false; + jboolean result = JNI_FALSE; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data *cb_data; + + + CONCURRENCY_LOCK(); + + /* Memory allocation for cb_data + * This is on the heap because it is used by libnfc + * even after this call has succesfully finished. It is only freed + * upon link closure in nfc_jni_llcp_linkStatus_callback. + */ + cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(cb_data, (void*)nat)) + { + goto clean_and_return; + } + + /* Check LLCP compliancy */ + TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, + nfc_jni_checkLlcp_callback, + nfc_jni_llcp_linkStatus_callback, + (void*)cb_data); + REENTRANCE_UNLOCK(); + /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol + * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + freeData = true; + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data->sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data->status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(cb_data); + if (freeData) { + free(cb_data); + } + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Activate(hLlcpHandle); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_FALSE; + } +} + + + +static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, + jint nSap, jstring sn) +{ + NFCSTATUS ret; + jobject connectionlessSocket = NULL; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_native_data *nat; + phNfc_sData_t sWorkingBuffer = {NULL, 0}; + phNfc_sData_t serviceName = {NULL, 0}; + phLibNfc_Llcp_sLinkParameters_t sParams; + jclass clsNativeConnectionlessSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Allocate Working buffer length */ + phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); + sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, + NULL, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + + /* Create new NativeLlcpConnectionlessSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + { + goto error; + } + + /* Get NativeConnectionless class object */ + clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); + if(e->ExceptionCheck()) + { + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); + e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); + TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); + + /* Set the miu link of the connectionless socket */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); + e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); + TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); + e->SetIntField(connectionlessSocket, f,(jint)nSap); + TRACE("Connectionless socket SAP = %d\n",nSap); + + return connectionlessSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + + if (sWorkingBuffer.buffer != NULL) { + free(sWorkingBuffer.buffer); + } + + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + phNfc_sData_t serviceName; + struct nfc_jni_native_data *nat; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + ret = phLibNfc_Llcp_Close(hLlcpSocket); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Listen( hLlcpSocket, + nfc_jni_llcp_transport_listen_socket_callback, + (void*)hLlcpSocket); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + /* Close created socket */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpServiceSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + { + ALOGE("Llcp Socket object creation error"); + goto error; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); + if(e->ExceptionCheck()) + { + ALOGE("Llcp Socket get object class error"); + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); + TRACE("Service socket Handle = %02x\n",hLlcpSocket); + + /* Set socket linear buffer length */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField(serviceSocket, f,(jint)linearBufferLength); + TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField(serviceSocket, f,(jint)miu); + TRACE("Service socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField(serviceSocket, f,(jint)rw); + TRACE("Service socket RW = %d\n",rw); + + return serviceSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + struct nfc_jni_native_data *nat; + jclass clsNativeLlcpSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + return NULL; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGE("Llcp socket object creation error"); + return NULL; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGE("Get class object error"); + return NULL; + } + + /* Test if an SAP number is present */ + if(nSap != 0) + { + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + return NULL; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField(clientSocket, f,(jint)nSap); + TRACE("socket SAP = %d\n",nSap); + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hLlcpSocket); + TRACE("socket Handle = %02x\n",hLlcpSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + TRACE("socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + TRACE("socket RW = %d\n",rw); + + + return clientSocket; +} + +static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) +{ + TRACE("Last Error Status = 0x%02x",lastErrorStatus); + + if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) + { + return ERROR_BUFFER_TOO_SMALL; + } + else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) + { + return ERROR_INSUFFICIENT_RESOURCES; + } + else + { + return lastErrorStatus; + } +} + +static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) +{ + emergency_recovery(NULL); +} + +static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting init modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_initiator_modes = modes; +} + +static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting target modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_target_modes = modes; +} + +static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { + bool result = FALSE; + int load_result; + bool wasDisabled = FALSE; + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + NFCSTATUS status = NFCSTATUS_FAILED; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + result = FALSE; + goto clean_and_return; + } + + if (takeLock) + { + CONCURRENCY_LOCK(); + } + + /* Initialize Driver */ + if(!driverConfigured) + { + result = nfc_jni_configure_driver(nat); + wasDisabled = TRUE; + } + TRACE("com_android_nfc_NfcManager_doDownload()"); + + TRACE("Go in Download Mode"); + phLibNfc_Download_Mode(); + + TRACE("Load new Firmware Image"); + load_result = phLibNfc_Load_Firmware_Image(); + if(load_result != 0) + { + TRACE("Load new Firmware Image - status = %d",load_result); + result = FALSE; + goto clean_and_return; + } + + // Download + gInputParam.buffer = InputBuffer; + gInputParam.length = 0x01; + gOutputParam.buffer = OutputBuffer; + gOutputParam.length = 0x01; + + ALOGD("Download new Firmware"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + result = FALSE; + goto clean_and_return; + } + + /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we + try to download an old-style firmware on top of a new-style + firmware. Hence, this is expected behavior, and not an + error condition. */ + if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); + } + + /*Download is successful*/ + result = TRUE; +clean_and_return: + TRACE("phLibNfc_HW_Reset()"); + phLibNfc_HW_Reset(); + /* Deinitialize Driver */ + if(wasDisabled) + { + result = nfc_jni_unconfigure_driver(nat); + } + if (takeLock) + { + CONCURRENCY_UNLOCK(); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + return performDownload(nat, true); +} + +static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); + return e->NewStringUTF(buffer); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)com_android_nfc_NfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void *)com_android_nfc_NfcManager_init_native_struc}, + + {"doInitialize", "()Z", + (void *)com_android_nfc_NfcManager_initialize}, + + {"doDeinitialize", "()Z", + (void *)com_android_nfc_NfcManager_deinitialize}, + + {"enableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)com_android_nfc_NfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)com_android_nfc_NfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)com_android_nfc_NfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)com_android_nfc_NfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)com_android_nfc_NfcManager_doAbort}, + + {"doSetP2pInitiatorModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)com_android_nfc_NfcManager_doDump}, +}; + + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e) +{ + nfc_jni_native_monitor_t *nfc_jni_native_monitor; + + nfc_jni_native_monitor = nfc_jni_init_monitor(); + if(nfc_jni_native_monitor == NULL) + { + ALOGE("NFC Manager cannot recover native monitor %x\n", errno); + return -1; + } + + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; iRemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;iNewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/jni/com_android_nfc_list.cpp b/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/jni/com_android_nfc_list.h b/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk deleted file mode 100644 index 8ae792a..0000000 --- a/nxp/jni/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES:= \ - com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ - com_android_nfc_NativeLlcpServiceSocket.cpp \ - com_android_nfc_NativeLlcpSocket.cpp \ - com_android_nfc_NativeNfcManager.cpp \ - com_android_nfc_NativeNfcTag.cpp \ - com_android_nfc_NativeP2pDevice.cpp \ - com_android_nfc_NativeNfcSecureElement.cpp \ - com_android_nfc_list.cpp \ - com_android_nfc.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/libnfc-nxp/src \ - external/libnfc-nxp/inc - -LOCAL_SHARED_LIBRARIES := \ - libnativehelper \ - libcutils \ - libutils \ - libnfc \ - libhardware - -#LOCAL_CFLAGS += -O0 -g - -LOCAL_MODULE := libnfc_jni -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp deleted file mode 100644 index d794d6e..0000000 --- a/nxp/jni/com_android_nfc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "errno.h" -#include "com_android_nfc.h" -#include "com_android_nfc_list.h" -#include "phLibNfcStatus.h" - -/* - * JNI Initialization - */ -jint JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - JNIEnv *e; - - ALOGD("NFC Service : loading JNI\n"); - - // Check JNI version - if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) - return JNI_ERR; - - android::vm = jvm; - - if (android::register_com_android_nfc_NativeNfcManager(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcTag(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) - return JNI_ERR; - - return JNI_VERSION_1_6; -} - -namespace android { - -extern struct nfc_jni_native_data *exported_nat; - -JavaVM *vm; - -/* - * JNI Utils - */ -JNIEnv *nfc_get_env() -{ - JNIEnv *e; - if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Current thread is not attached to VM"); - phLibNfc_Mgt_Recovery(); - abort(); - } - return e; -} - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) -{ - /* Create semaphore */ - if(sem_init(&pCallbackData->sem, 0, 0) == -1) - { - ALOGE("Semaphore creation failed (errno=0x%08x)", errno); - return false; - } - - /* Set default status value */ - pCallbackData->status = NFCSTATUS_FAILED; - - /* Copy the context */ - pCallbackData->pContext = pContext; - - /* Add to active semaphore list */ - if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to add the semaphore to the list"); - } - - return true; -} - -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) -{ - /* Destroy semaphore */ - if (sem_destroy(&pCallbackData->sem)) - { - ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); - } - - /* Remove from active semaphore list */ - if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to remove semaphore from the list"); - } - -} - -void nfc_cb_data_releaseAll() -{ - nfc_jni_callback_data* pCallbackData; - - while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) - { - pCallbackData->status = NFCSTATUS_FAILED; - sem_post(&pCallbackData->sem); - } -} - -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj) -{ - jclass cls; - jobject obj; - jmethodID ctor; - - cls = e->FindClass(clsname); - if(cls == NULL) - { - return -1; - ALOGD("Find class error\n"); - } - - - ctor = e->GetMethodID(cls, "", "()V"); - - obj = e->NewObject(cls, ctor); - if(obj == NULL) - { - return -1; - ALOGD("Create object error\n"); - } - - *cached_obj = e->NewGlobalRef(obj); - if(*cached_obj == NULL) - { - e->DeleteLocalRef(obj); - ALOGD("Global ref error\n"); - return -1; - } - - e->DeleteLocalRef(obj); - - return 0; -} - - -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - /* Retrieve native structure address */ - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mNative", "I"); - return (struct nfc_jni_native_data*)e->GetIntField(o, f); -} - -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) -{ - return exported_nat; -} - -static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; - -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) -{ - - pthread_mutexattr_t recursive_attr; - - pthread_mutexattr_init(&recursive_attr); - pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); - - if(nfc_jni_native_monitor == NULL) - { - nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); - } - - if(nfc_jni_native_monitor != NULL) - { - memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); - - if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) - { - ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) - { - ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(!listInit(&nfc_jni_native_monitor->sem_list)) - { - ALOGE("NFC Manager Semaphore List creation failed"); - return NULL; - } - - LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); - - if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) - { - ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) - { - ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); - return NULL; - } - -} - - return nfc_jni_native_monitor; -} - -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) -{ - return nfc_jni_native_monitor; -} - - -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mMode", "S"); - - return e->GetShortField(o, f); -} - - -int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) -{ - - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedTechIndex", "I"); - - return e->GetIntField(o, f); - -} - -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - int connectedTech = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); - - if ((connectedTechIndex != -1) && (techTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(techTypes))) { - jint* technologies = e->GetIntArrayElements(techTypes, 0); - if (technologies != NULL) { - connectedTech = technologies[connectedTechIndex]; - e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); - } - } - - return connectedTech; - -} - -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jint connectedLibNfcType = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); - jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); - - if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { - jint* types = e->GetIntArrayElements(libNfcTypes, 0); - if (types != NULL) { - connectedLibNfcType = types[connectedTechIndex]; - e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); - } - } - return connectedLibNfcType; - -} - -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedHandle", "I"); - - return e->GetIntField(o, f); -} - -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jintArray techtypes; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechList","[I"); - - /* Read the techtypes */ - techtypes = (jintArray) e->GetObjectField(o, f); - - return techtypes; -} - - - -//Display status code -const char* nfc_jni_get_status_name(NFCSTATUS status) -{ - #define STATUS_ENTRY(status) { status, #status } - - struct status_entry { - NFCSTATUS code; - const char *name; - }; - - const struct status_entry sNameTable[] = { - STATUS_ENTRY(NFCSTATUS_SUCCESS), - STATUS_ENTRY(NFCSTATUS_FAILED), - STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), - STATUS_ENTRY(NFCSTATUS_TARGET_LOST), - STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), - STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), - STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_SHUTDOWN), - STATUS_ENTRY(NFCSTATUS_ABORTED), - STATUS_ENTRY(NFCSTATUS_REJECTED ), - STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), - STATUS_ENTRY(NFCSTATUS_PENDING), - STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), - STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), - STATUS_ENTRY(NFCSTATUS_BUSY), - STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), - STATUS_ENTRY(NFCSTATUS_DESELECTED), - STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), - STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), - STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), - STATUS_ENTRY(NFCSTATUS_RF_ERROR), - STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), - STATUS_ENTRY(NFCSTATUS_INVALID_STATE), - STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), - STATUS_ENTRY(NFCSTATUS_RELEASED), - STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), - STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), - STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_READ_FAILED), - STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), - STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), - STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), - STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), - STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), - STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), - }; - - int i = sizeof(sNameTable)/sizeof(status_entry); - - while(i>0) - { - i--; - if (sNameTable[i].code == PHNFCSTATUS(status)) - { - return sNameTable[i].name; - } - } - - return "UNKNOWN"; -} - -int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, - int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { - bool found = false; - for (int i = 0; i < listSize; i++) { - if (techList[i] == techToAdd) { - found = true; - break; - } - } - if (!found && listSize < maxListSize) { - techList[listSize] = techToAdd; - handleList[listSize] = handleToAdd; - typeList[listSize] = typeToAdd; - return listSize + 1; - } - else { - return listSize; - } -} - - -#define MAX_NUM_TECHNOLOGIES 32 - -/* - * Utility to get a technology tree and a corresponding handle list from a detected tag. - */ -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* libnfcTypeList) -{ - int technologies[MAX_NUM_TECHNOLOGIES]; - int handles[MAX_NUM_TECHNOLOGIES]; - int libnfctypes[MAX_NUM_TECHNOLOGIES]; - - int index = 0; - // TODO: This counts from up to down because on multi-protocols, the - // ISO handle is usually the second, and we prefer the ISO. Should implement - // a method to find the "preferred handle order" and use that instead, - // since we shouldn't have dependencies on the tech list ordering. - for (int target = count - 1; target >= 0; target--) { - int type = devList[target].psRemoteDevInfo->RemDevType; - int handle = devList[target].hTargetDev; - switch (type) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - break; - } - case phNfc_eISO14443_4B_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO14443_3A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - case phNfc_eISO14443_B_PICC: - { - // TODO a bug in libnfc will cause 14443-3B only cards - // to be returned as this type as well, but these cards - // are very rare. Hence assume it's -4B - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO15693_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); - }break; - case phNfc_eMifare_PICC: - { - // We don't want to be too clever here; libnfc has already determined - // it's a Mifare, so we only check for UL, for all other tags - // we assume it's a mifare classic. This should make us more - // future-proof. - int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; - switch(sak) - { - case 0x00: - // could be UL or UL-C - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); - break; - default: - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); - break; - } - }break; - case phNfc_eFelica_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); - }break; - case phNfc_eJewel_PICC: - { - // Jewel represented as NfcA - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - default: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); - } - } - } - - // Build the Java arrays - if (techList != NULL) { - *techList = e->NewIntArray(index); - e->SetIntArrayRegion(*techList, 0, index, technologies); - } - - if (handleList != NULL) { - *handleList = e->NewIntArray(index); - e->SetIntArrayRegion(*handleList, 0, index, handles); - } - - if (libnfcTypeList != NULL) { - *libnfcTypeList = e->NewIntArray(index); - e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); - } -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h deleted file mode 100644 index b876dad..0000000 --- a/nxp/jni/com_android_nfc.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_JNI_H__ -#define __COM_ANDROID_NFC_JNI_H__ - -#define LOG_TAG "NFCJNI" - -#include -#include - -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include - -} -#include // for property_get - - -/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ -#define DISCOVERY_MODE_TAG_READER 0 -#define DISCOVERY_MODE_NFCIP1 1 -#define DISCOVERY_MODE_CARD_EMULATION 2 - -#define DISCOVERY_MODE_TABLE_SIZE 3 - -#define DISCOVERY_MODE_DISABLED 0 -#define DISCOVERY_MODE_ENABLED 1 - -#define MODE_P2P_TARGET 0 -#define MODE_P2P_INITIATOR 1 - -/* Properties values */ -#define PROPERTY_LLCP_LTO 0 -#define PROPERTY_LLCP_MIU 1 -#define PROPERTY_LLCP_WKS 2 -#define PROPERTY_LLCP_OPT 3 -#define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 -#define PROPERTY_NFC_DISCOVERY_F 6 -#define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 - -/* Error codes */ -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -/* Pre-defined card read/write state values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_UNKNOWN_TYPE -1 -#define NDEF_TYPE1_TAG 1 -#define NDEF_TYPE2_TAG 2 -#define NDEF_TYPE3_TAG 3 -#define NDEF_TYPE4_TAG 4 -#define NDEF_MIFARE_CLASSIC_TAG 101 -#define NDEF_ICODE_SLI_TAG 102 - -/* Pre-defined tag type values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_MODE_READ_ONLY 1 -#define NDEF_MODE_READ_WRITE 2 -#define NDEF_MODE_UNKNOWN 3 - - -/* Name strings for target types. These *must* match the values in TagTechnology.java */ -#define TARGET_TYPE_UNKNOWN -1 -#define TARGET_TYPE_ISO14443_3A 1 -#define TARGET_TYPE_ISO14443_3B 2 -#define TARGET_TYPE_ISO14443_4 3 -#define TARGET_TYPE_FELICA 4 -#define TARGET_TYPE_ISO15693 5 -#define TARGET_TYPE_NDEF 6 -#define TARGET_TYPE_NDEF_FORMATABLE 7 -#define TARGET_TYPE_MIFARE_CLASSIC 8 -#define TARGET_TYPE_MIFARE_UL 9 - -#define SMX_SECURE_ELEMENT_ID 11259375 - -/* Maximum byte length of an AID. */ -#define AID_MAXLEN 16 - -/* Utility macros for logging */ -#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN - -#if 0 - #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); - #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) - #define TRACE_ENABLED 1 -#else - #define LOG_CALLBACK(...) - #define TRACE(...) - #define TRACE_ENABLED 0 -#endif - -struct nfc_jni_native_data -{ - /* Thread handle */ - pthread_t thread; - int running; - - /* Our VM */ - JavaVM *vm; - int env_version; - - /* Reference to the NFCManager instance */ - jobject manager; - - /* Cached objects */ - jobject cached_NfcTag; - jobject cached_P2pDevice; - - /* Target discovery configuration */ - int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - - /* Secure Element selected */ - int seId; - - /* LLCP params */ - int lto; - int miu; - int wks; - int opt; - - /* Tag detected */ - jobject tag; - - /* Lib Status */ - NFCSTATUS status; - - /* p2p modes */ - int p2p_initiator_modes; - int p2p_target_modes; - -}; - -typedef struct nfc_jni_native_monitor -{ - /* Mutex protecting native library against reentrance */ - pthread_mutex_t reentrance_mutex; - - /* Mutex protecting native library against concurrency */ - pthread_mutex_t concurrency_mutex; - - /* List used to track pending semaphores waiting for callback */ - struct listHead sem_list; - - /* List used to track incoming socket requests (and associated sync variables) */ - LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; - pthread_mutex_t incoming_socket_mutex; - pthread_cond_t incoming_socket_cond; - -} nfc_jni_native_monitor_t; - -typedef struct nfc_jni_callback_data -{ - /* Semaphore used to wait for callback */ - sem_t sem; - - /* Used to store the status sent by the callback */ - NFCSTATUS status; - - /* Used to provide a local context to the callback */ - void* pContext; - -} nfc_jni_callback_data_t; - -typedef struct nfc_jni_listen_data -{ - /* LLCP server socket receiving the connection request */ - phLibNfc_Handle pServerSocket; - - /* LLCP socket created from the connection request */ - phLibNfc_Handle pIncomingSocket; - - /* List entries */ - LIST_ENTRY(nfc_jni_listen_data) entries; - -} nfc_jni_listen_data_t; - -/* TODO: treat errors and add traces */ -#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) -#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) -#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) -#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) - -namespace android { - -extern JavaVM *vm; - -JNIEnv *nfc_get_env(); - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); -void nfc_cb_data_releaseAll(); - -const char* nfc_jni_get_status_name(NFCSTATUS status); -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj); -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); - -int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* typeList); - -/* P2P */ -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); - -/* TAG */ -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); - -/* LLCP */ -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e); -int register_com_android_nfc_NativeNfcTag(JNIEnv *e); -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); - -} // namespace android - -#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp deleted file mode 100644 index 188edb4..0000000 --- a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - pCallbackData->pContext = (void*)ssap; - TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_sendTo_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* -* Methods -*/ -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_SendTo()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SendTo(hRemoteDevice, - hLlcpSocket, - nsap, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) -{ - NFCSTATUS ret; - struct timespec ts; - uint8_t ssap; - jobject llcpPacket = NULL; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer; - jclass clsLlcpPacket; - jfieldID f; - jbyteArray receivedData = NULL; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create new LlcpPacket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) - { - ALOGE("Find LlcpPacket class error"); - goto clean_and_return; - } - - /* Get NativeConnectionless class object */ - clsLlcpPacket = e->GetObjectClass(llcpPacket); - if(e->ExceptionCheck()) - { - ALOGE("Get Object class error"); - goto clean_and_return; - } - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); - - sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); - sReceiveBuffer.length = linkMiu; - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - &cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ssap = (uint32_t)cb_data.pContext; - TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); - - /* Set Llcp Packet remote SAP */ - f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); - e->SetIntField(llcpPacket, f,(jbyte)ssap); - - /* Set Llcp Packet Buffer */ - ALOGD("Set LlcpPacket Data Buffer\n"); - f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); - receivedData = e->NewByteArray(sReceiveBuffer.length); - e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); - e->SetObjectField(llcpPacket, f, receivedData); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return llcpPacket; -} - -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - TRACE("Close Connectionless socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, - - {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, - - {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", - gMethods, NELEM(gMethods)); -} - -} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp deleted file mode 100644 index 92de3e4..0000000 --- a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode); -/* - * Callbacks - */ -static void nfc_jni_llcp_accept_socket_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -/* - * Utils - */ - -static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, - phLibNfc_Handle hServerSocket) -{ - nfc_jni_listen_data_t * pListenData; - phLibNfc_Handle pIncomingSocket = NULL; - - /* Look for a pending incoming connection on the current server */ - LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) - { - if (pListenData->pServerSocket == hServerSocket) - { - pIncomingSocket = pListenData->pIncomingSocket; - LIST_REMOVE(pListenData, entries); - free(pListenData); - break; - } - } - - return pIncomingSocket; -} - -/* - * Methods - */ -static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret = NFCSTATUS_SUCCESS; - struct timespec ts; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - jfieldID f; - jclass clsNativeLlcpSocket; - jobject clientSocket = NULL; - struct nfc_jni_callback_data cb_data; - phLibNfc_Handle hIncomingSocket, hServerSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Get server socket */ - hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Set socket options with the socket options of the service */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - - while(cb_data.status != NFCSTATUS_SUCCESS) - { - /* Wait for tag Notification */ - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { - pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); - } - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - /* Accept the incomming socket */ - TRACE("phLibNfc_Llcp_Accept()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Accept( hIncomingSocket, - &sOptions, - &sWorkingBuffer, - nfc_jni_llcp_transport_socket_err_callback, - nfc_jni_llcp_accept_socket_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - // NOTE: This may happen if link went down since incoming socket detected, then - // just drop it and start a new accept loop. - ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - continue; - } - TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ - ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); - } - } - - /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGD("LLCP Socket creation error"); - goto clean_and_return; - } - - /* Get NativeConnectionOriented class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGD("LLCP Socket get class object error"); - goto clean_and_return; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hIncomingSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - - TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return clientSocket; -} - -static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - TRACE("Close Service socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - /* TODO: implement accept abort */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("Close Service socket OK"); - return TRUE; - } - else - { - ALOGD("Close Service socket KO"); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_NativeLlcpServiceSocket_doAccept}, - - {"doClose", "()Z", - (void *)com_NativeLlcpServiceSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp deleted file mode 100644 index 0c0b830..0000000 --- a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_disconnect_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - TRACE("Socket connected\n"); - } - else - { - ALOGD("Socket not connected:"); - switch(nErrCode) - { - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: - { - ALOGD("> SAP NOT ACTIVE\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: - { - ALOGD("> SAP NOT FOUND\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: - { - ALOGD("> CONNECT REJECTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: - { - ALOGD("> CONNECT NOT ACCEPTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: - { - ALOGD("> SOCKET NOT AVAILABLE\n"); - }break; - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - - - -static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Methods - */ -static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_Llcp_Connect(%d)",nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Connect(hRemoteDevice, - hLlcpSocket, - nSap, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("LLCP Connect request failed"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) -{ - NFCSTATUS ret; - struct timespec ts; - phNfc_sData_t serviceName = {0}; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Service socket */ - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - - TRACE("phLibNfc_Llcp_ConnectByUri()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, - hLlcpSocket, - &serviceName, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_Send()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Send(hRemoteDevice, - hLlcpSocket, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jint result = -1; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); - sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); - - TRACE("phLibNfc_Llcp_Recv()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Recv(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_PENDING) - { - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - } - else if (ret == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - else - { - /* Return status should be either SUCCESS or PENDING */ - ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - -clean_and_return: - if (sReceiveBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.miu; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.rw; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnect}, - - {"doConnectBy", "(Ljava/lang/String;)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, - - {"doClose", "()Z", - (void *)com_android_nfc_NativeLlcpSocket_doClose}, - - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeLlcpSocket_doSend}, - - {"doReceive", "([B)I", - (void *)com_android_nfc_NativeLlcpSocket_doReceive}, - - {"doGetRemoteSocketMiu", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, - - {"doGetRemoteSocketRw", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, -}; - - -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp deleted file mode 100644 index e6da0fa..0000000 --- a/nxp/jni/com_android_nfc_NativeNfcManager.cpp +++ /dev/null @@ -1,2623 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "com_android_nfc.h" - -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -extern uint32_t libnfc_llc_error_count; - -static phLibNfc_sConfig_t gDrvCfg; -void *gHWRef; -static phNfc_sData_t gInputParam; -static phNfc_sData_t gOutputParam; - -uint8_t device_connected_flag; -static bool driverConfigured = FALSE; - -static phLibNfc_Handle hLlcpHandle; -static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; -static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; - -static jmethodID cached_NfcManager_notifyNdefMessageListeners; -static jmethodID cached_NfcManager_notifyTransactionListeners; -static jmethodID cached_NfcManager_notifyLlcpLinkActivation; -static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; -static jmethodID cached_NfcManager_notifyTargetDeselected; - -static jmethodID cached_NfcManager_notifySeFieldActivated; -static jmethodID cached_NfcManager_notifySeFieldDeactivated; - -static jmethodID cached_NfcManager_notifySeApduReceived; -static jmethodID cached_NfcManager_notifySeMifareAccess; -static jmethodID cached_NfcManager_notifySeEmvCardRemoval; - -namespace android { - -phLibNfc_Handle storedHandle = 0; - -struct nfc_jni_native_data *exported_nat = NULL; - -/* Internal functions declaration */ -static void *nfc_jni_client_thread(void *arg); -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_se_set_mode_callback(void *context, - phLibNfc_Handle handle, NFCSTATUS status); -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status); -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); -static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); - -/* - * Deferred callback called when client thread must be exited - */ -static void client_kill_deferred_call(void* arg) -{ - struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; - - nat->running = FALSE; -} - -static void kill_client(nfc_jni_native_data *nat) -{ - phDal4Nfc_Message_Wrapper_t wrapper; - phLibNfc_DeferredCall_t *pMsg; - - usleep(50000); - - ALOGD("Terminating client thread..."); - - pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); - pMsg->pCallback = client_kill_deferred_call; - pMsg->pParameter = (void*)nat; - - wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; - wrapper.msg.pMsgData = pMsg; - wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); - - phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); -} - -static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_ioctl_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_deinit_download_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) -{ - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - struct timespec ts; - NFCSTATUS status = NFCSTATUS_FAILED; - phLibNfc_StackCapabilities_t caps; - struct nfc_jni_callback_data cb_data; - bool result; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - if(update) - { - //deinit - TRACE("phLibNfc_Mgt_DeInitialize() (download)"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts)) - { - ALOGW("Deinitialization timed out (download)"); - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("Deinitialization FAILED (download)"); - } - TRACE("Deinitialization SUCCESS (download)"); - } - - result = performDownload(nat, false); - - if (!result) { - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - status = cb_data.status; - goto clean_and_return; - } - - /* ====== CAPABILITIES ======= */ - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /*Download is successful*/ - status = NFCSTATUS_SUCCESS; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return status; -} - -static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) -{ - char value[PROPERTY_VALUE_MAX]; - int result = FALSE; - NFCSTATUS status; - - /* ====== CONFIGURE DRIVER ======= */ - /* Configure hardware link */ - gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); - - TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); - REENTRANCE_UNLOCK(); - if(status == NFCSTATUS_ALREADY_INITIALISED) { - ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) - { - ALOGE("pthread_create failed"); - goto clean_and_return; - } - - driverConfigured = TRUE; - -clean_and_return: - return result; -} - -static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) -{ - int result = FALSE; - NFCSTATUS status; - - /* Unconfigure driver */ - TRACE("phLibNfc_Mgt_UnConfigureDriver()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); - } - else - { - ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = TRUE; - } - - driverConfigured = FALSE; - - return result; -} - -/* Initialization function */ -static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { - struct timespec ts; - uint8_t resp[16]; - NFCSTATUS status; - phLibNfc_StackCapabilities_t caps; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; - phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; - struct nfc_jni_callback_data cb_data; - uint8_t firmware_status; - uint8_t update = TRUE; - int result = JNI_FALSE; - const hw_module_t* hw_module; - nfc_pn544_device_t* pn544_dev = NULL; - int ret = 0; - ALOGD("Start Initialization\n"); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Get EEPROM values and device port from product-specific settings */ - ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); - if (ret) { - ALOGE("hw_get_module() failed."); - goto clean_and_return; - } - ret = nfc_pn544_open(hw_module, &pn544_dev); - if (ret) { - ALOGE("Could not open pn544 hw_module."); - goto clean_and_return; - } - if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { - ALOGE("Could not load EEPROM settings"); - goto clean_and_return; - } - - /* Reset device connected handle */ - device_connected_flag = 0; - - /* Reset stored handle */ - storedHandle = 0; - - /* Initialize Driver */ - if(!driverConfigured) - { - nfc_jni_configure_driver(nat); - } - - /* ====== INITIALIZE ======= */ - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - update = FALSE; - goto force_download; - } - TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - update = FALSE; - goto force_download; - } - - /* ====== CAPABILITIES ======= */ - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /* ====== FIRMWARE VERSION ======= */ - if(caps.psDevCapabilities.firmware_update_info) - { -force_download: - for (i=0; i<3; i++) - { - TRACE("Firmware version not UpToDate"); - status = nfc_jni_download_locked(nat, update); - if(status == NFCSTATUS_SUCCESS) - { - ALOGI("Firmware update SUCCESS"); - break; - } - ALOGW("Firmware update FAILED"); - update = FALSE; - } - if(i>=3) - { - ALOGE("Unable to update firmware, giving up"); - goto clean_and_return; - } - } - else - { - TRACE("Firmware version UpToDate"); - } - /* ====== EEPROM SETTINGS ======= */ - - // Update EEPROM settings - TRACE("****** START EEPROM SETTINGS UPDATE ******"); - for (i = 0; i < pn544_dev->num_eeprom_settings; i++) - { - char eeprom_property[PROPERTY_KEY_MAX]; - char eeprom_value[PROPERTY_VALUE_MAX]; - uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); - TRACE("> EEPROM SETTING: %d", i); - - // Check for override of this EEPROM value in properties - snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", - eeprom_base[1], eeprom_base[2]); - TRACE(">> Checking property: %s", eeprom_property); - if (property_get(eeprom_property, eeprom_value, "") == 2) { - int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); - ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", - eeprom_base[1], eeprom_base[2], eeprom_value_num); - eeprom_base[3] = eeprom_value_num; - } - - TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], - eeprom_base[3]); - gInputParam.buffer = eeprom_base; - gInputParam.length = 0x04; - gOutputParam.buffer = resp; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if (cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - } - TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); - - /* ====== SECURE ELEMENTS ======= */ - - REENTRANCE_LOCK(); - ALOGD("phLibNfc_SE_GetSecureElementList()"); - status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - - ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i < No_SE; i++) - { - if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); - } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); - } - - /* Set SE mode - Off */ - REENTRANCE_LOCK(); - status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, - phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - } - - /* ====== LLCP ======= */ - - /* LLCP Params */ - TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); - LlcpConfigInfo.miu = nat->miu; - LlcpConfigInfo.lto = nat->lto; - LlcpConfigInfo.wks = nat->wks; - LlcpConfigInfo.option = nat->opt; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, - nfc_jni_llcpcfg_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* ===== DISCOVERY ==== */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.Duration = 300000; /* in ms */ - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Register for the card emulation mode */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); - - - /* ====== END ======= */ - - ALOGI("NFC Initialized"); - - result = TRUE; - -clean_and_return: - if (result != TRUE) - { - if(nat) - { - kill_client(nat); - } - } - if (pn544_dev != NULL) { - nfc_pn544_close(pn544_dev); - } - nfc_cb_data_deinit(&cb_data); - - return result; -} - -static int is_user_build() { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.type", value, ""); - return !strncmp("user", value, PROPERTY_VALUE_MAX); -} - -/* - * Last-chance fallback when there is no clean way to recover - * Performs a software reset - */ -void emergency_recovery(struct nfc_jni_native_data *nat) { - if (!is_user_build()) { - ALOGE("emergency_recovery: force restart of NFC service"); - } else { - // dont recover immediately, so we can debug - unsigned int t; - for (t=1; t < 1000000; t <<= 1) { - ALOGE("emergency_recovery: NFC stack dead-locked"); - sleep(t); - } - } - phLibNfc_Mgt_Recovery(); - abort(); // force a noisy crash -} - -void nfc_jni_reset_timeout_values() -{ - REENTRANCE_LOCK(); - phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); - phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); - phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); - phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); - REENTRANCE_UNLOCK(); -} - -/* - * Restart the polling loop when unable to perform disconnect - */ -void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) -{ - nfc_jni_start_discovery_locked(nat, true); -} - - /* - * Utility to recover UID from target infos - */ -static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - phNfc_sData_t uid; - - switch(psRemoteDevInfo->RemDevType) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_3A_PICC: - case phNfc_eMifare_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; - break; - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; - uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); - break; - case phNfc_eFelica_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; - uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; - break; - case phNfc_eJewel_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; - break; - case phNfc_eISO15693_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; - break; - case phNfc_eNfcIP1_Target: - case phNfc_eNfcIP1_Initiator: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; - uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; - break; - default: - uid.buffer = NULL; - uid.length = 0; - break; - } - - return uid; -} - -/* - * NFC stack message processing - */ -static void *nfc_jni_client_thread(void *arg) -{ - struct nfc_jni_native_data *nat; - JNIEnv *e; - JavaVMAttachArgs thread_args; - phDal4Nfc_Message_Wrapper_t wrapper; - - nat = (struct nfc_jni_native_data *)arg; - - thread_args.name = "NFC Message Loop"; - thread_args.version = nat->env_version; - thread_args.group = NULL; - - nat->vm->AttachCurrentThread(&e, &thread_args); - pthread_setname_np(pthread_self(), "message"); - - TRACE("NFC client started"); - nat->running = TRUE; - while(nat->running == TRUE) - { - /* Fetch next message from the NFC stack message queue */ - if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, - sizeof(phLibNfc_Message_t), 0, 0) == -1) - { - ALOGE("NFC client received bad message"); - continue; - } - - switch(wrapper.msg.eMsgType) - { - case PH_LIBNFC_DEFERREDCALL_MSG: - { - phLibNfc_DeferredCall_t *msg = - (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); - - REENTRANCE_LOCK(); - msg->pCallback(msg->pParameter); - REENTRANCE_UNLOCK(); - - break; - } - } - } - TRACE("NFC client stopped"); - - nat->vm->DetachCurrentThread(); - - return NULL; -} - -extern uint8_t nfc_jni_is_ndef; -extern uint8_t *nfc_jni_ndef_buf; -extern uint32_t nfc_jni_ndef_buf_len; - -static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = -{ - 3, - { 0x46, 0x66, 0x6D } -}; - -/* - * Callbacks - */ - -/* P2P - LLCP callbacks */ -static void nfc_jni_llcp_linkStatus_callback(void *pContext, - phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) -{ - phFriNfc_Llcp_sLinkParameters_t sLinkParams; - JNIEnv *e; - NFCSTATUS status; - - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; - - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - /* Update link status */ - g_eLinkStatus = eLinkStatus; - - if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) - { - REENTRANCE_LOCK(); - status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGW("GetRemote Info failded - Status = %02x",status); - } - else - { - ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, - sLinkParams.miu, - sLinkParams.option, - sLinkParams.wks); - device_connected_flag = 1; - } - } - else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) - { - ALOGI("LLCP Link deactivated"); - free(pContextData); - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Reset incoming socket list */ - while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) - { - pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); - LIST_REMOVE(pListenData, entries); - free(pListenData); - } - - /* Notify manager that the LLCP is lost or deactivated */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } -} - -static void nfc_jni_checkLlcp_callback(void *context, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; - - LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, - phLibNfc_Handle hIncomingSocket) -{ - phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - - /* Store the connection request */ - pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); - if (pListenData == NULL) - { - ALOGE("Failed to create structure to handle incoming LLCP connection request"); - goto clean_and_return; - } - pListenData->pServerSocket = hServiceSocket; - pListenData->pIncomingSocket = hIncomingSocket; - LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); - - /* Signal pending accept operations that the list is updated */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - -clean_and_return: - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); -} - -void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode) -{ - PHNFC_UNUSED_VARIABLE(pContext); - - TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); - - if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) - { - ALOGW("Frame Rejected - Disconnected"); - } - else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) - { - ALOGD("Socket Disconnected"); - } -} - - -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_discover_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNoOfRemoteDev) -{ - // Always prefer p2p targets over other targets. Otherwise, select the first target - // reported. - uint8_t preferred_index = 0; - for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { - if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { - preferred_index = i; - } - } - return preferred_index; -} - -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status) -{ - JNIEnv *e; - NFCSTATUS ret; - jclass tag_cls = NULL; - jobject target_array; - jobject tag; - jmethodID ctor; - jfieldID f; - const char * typeName; - jbyteArray tagUid; - jbyteArray generalBytes = NULL; - struct nfc_jni_native_data *nat; - struct timespec ts; - phNfc_sData_t data; - int i; - int target_index = 0; // Target that will be reported (if multiple can be >0) - - nat = (struct nfc_jni_native_data *)pContext; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); - - /* Notify manager that a target was deselected */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); - TRACE("Discovered %d tags", uNofRemoteDev); - - target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); - - /* Reset device connected flag */ - device_connected_flag = 1; - phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; - phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - - tag_cls = e->GetObjectClass(nat->cached_P2pDevice); - if(e->ExceptionCheck()) - { - ALOGE("Get Object Class Error"); - kill_client(nat); - return; - } - - /* New target instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - /* Set P2P Target mode */ - f = e->GetFieldID(tag_cls, "mMode", "I"); - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - ALOGD("Discovered P2P Initiator"); - e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); - } - else - { - ALOGD("Discovered P2P Target"); - e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); - } - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - /* Set General Bytes */ - f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes length ="); - for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) - { - ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); - } - - generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - - e->SetByteArrayRegion(generalBytes, 0, - remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, - (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); - - e->SetObjectField(tag, f, generalBytes); - } - - /* Set tag handle */ - f = e->GetFieldID(tag_cls, "mHandle", "I"); - e->SetIntField(tag, f,(jint)remDevHandle); - TRACE("Target handle = 0x%08x",remDevHandle); - } - else - { - tag_cls = e->GetObjectClass(nat->cached_NfcTag); - if(e->ExceptionCheck()) - { - kill_client(nat); - return; - } - - /* New tag instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - bool multi_protocol = false; - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - TRACE("Multiple Protocol TAG detected\n"); - multi_protocol = true; - } - - /* Set tag UID */ - f = e->GetFieldID(tag_cls, "mUid", "[B"); - data = get_target_uid(remDevInfo); - tagUid = e->NewByteArray(data.length); - if(data.length > 0) - { - e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); - } - e->SetObjectField(tag, f, tagUid); - - /* Generate technology list */ - jintArray techList; - jintArray handleList; - jintArray typeList; - nfc_jni_get_technology_tree(e, psRemoteDevList, - multi_protocol ? uNofRemoteDev : 1, - &techList, &handleList, &typeList); - - /* Push the technology list into the java object */ - f = e->GetFieldID(tag_cls, "mTechList", "[I"); - e->SetObjectField(tag, f, techList); - - f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); - e->SetObjectField(tag, f, handleList); - - f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); - e->SetObjectField(tag, f, typeList); - - f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); - e->SetIntField(tag, f,(jint)-1); - - f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); - e->SetIntField(tag, f,(jint)-1); - } - - storedHandle = remDevHandle; - if (nat->tag != NULL) { - e->DeleteGlobalRef(nat->tag); - } - nat->tag = e->NewGlobalRef(tag); - - /* Notify the service */ - TRACE("Notify Nfc Service"); - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - /* Store the hanlde of the P2P device */ - hLlcpHandle = remDevHandle; - - /* Notify manager that new a P2P device was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - /* Notify manager that new a tag was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - e->DeleteLocalRef(tag); - } -} - -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_init_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_deinit_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Card Emulation callback */ -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) -{ - JNIEnv *e; - jobject tmp_array = NULL; - jobject mifare_block = NULL; - struct nfc_jni_native_data *nat; - phNfc_sData_t *aid; - phNfc_sData_t *mifare_command; - struct nfc_jni_callback_data *pCallbackData; - int i=0; - - LOG_CALLBACK("nfc_jni_transaction_callback", status); - - nat = (struct nfc_jni_native_data *)context; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_SUCCESS) - { - switch(evt_type) - { - case phLibNfc_eSE_EvtStartTransaction: - { - TRACE("> SE EVT_START_TRANSACTION"); - if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) - { - aid = &(evt_info->UiccEvtInfo.aid); - - ALOGD("> AID DETECTED"); - - if(aid != NULL) - { - if (TRACE_ENABLED == 1) { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); - } - ALOGD("> AID: %s", aid_str); - } - tmp_array = e->NewByteArray(aid->length); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - goto error; - } - - TRACE("Notify Nfc Service"); - /* Notify manager that a new event occurred on a SE */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - ALOGD("> NO AID DETECTED"); - } - }break; - - case phLibNfc_eSE_EvtApduReceived: - { - phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); - TRACE("> SE EVT_APDU_RECEIVED"); - - if (apdu != NULL) { - TRACE(" APDU length=%d", apdu->length); - tmp_array = e->NewByteArray(apdu->length); - if (tmp_array == NULL) { - goto error; - } - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); - if (e->ExceptionCheck()) { - goto error; - } - } else { - TRACE(" APDU EMPTY"); - } - - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); - }break; - - case phLibNfc_eSE_EvtCardRemoval: - { - TRACE("> SE EVT_EMV_CARD_REMOVAL"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); - }break; - - case phLibNfc_eSE_EvtMifareAccess: - { - TRACE("> SE EVT_MIFARE_ACCESS"); - mifare_command = &(evt_info->UiccEvtInfo.aid); - TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); - tmp_array = e->NewByteArray(2); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); - }break; - - case phLibNfc_eSE_EvtFieldOn: - { - TRACE("> SE EVT_FIELD_ON"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); - }break; - - case phLibNfc_eSE_EvtFieldOff: - { - TRACE("> SE EVT_FIELD_OFF"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); - }break; - - default: - { - TRACE("Unknown SE event"); - }break; - } - } - else - { - ALOGE("SE transaction notification error"); - goto error; - } - - /* Function finished, now clean and return */ - goto clean_and_return; - - error: - /* In case of error, just discard the notification */ - ALOGE("Failed to send SE transaction notification"); - e->ExceptionClear(); - - clean_and_return: - if(tmp_array != NULL) - { - e->DeleteLocalRef(tmp_array); - } -} - -static void nfc_jni_se_set_mode_callback(void *pContext, - phLibNfc_Handle handle, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* - * NFCManager methods - */ - -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) -{ - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ - nfc_jni_reset_timeout_values(); - - /* Reload the p2p modes */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Start Polling loop */ - TRACE("****** Start NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, - nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - -static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) -{ - phLibNfc_sADD_Cfg_t discovery_cfg; - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - discovery_cfg.PollDevInfo.PollEnabled = 0; - discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; - discovery_cfg.NfcIP_Target_Mode = 0; - discovery_cfg.NfcIP_Tgt_Disable = TRUE; - - /* Start Polling loop */ - TRACE("****** Stop NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - - -static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nfc_jni_stop_discovery_locked(nat); - - CONCURRENCY_UNLOCK(); - -} - -static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - nat = nfc_jni_get_nat(e, o); - - /* Register callback for remote device notifications. - * Must re-register every time we turn on discovery, since other operations - * (such as opening the Secure Element) can change the remote device - * notification callback*/ - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", - nat->registry_info.Jewel==TRUE?"J":"", - nat->registry_info.MifareUL==TRUE?"UL":"", - nat->registry_info.MifareStd==TRUE?"Mi":"", - nat->registry_info.Felica==TRUE?"F":"", - nat->registry_info.ISO14443_4A==TRUE?"4A":"", - nat->registry_info.ISO14443_4B==TRUE?"4B":"", - nat->registry_info.NFC==TRUE?"P2P":"", - nat->registry_info.ISO15693==TRUE?"R":"", ret); - - nfc_jni_start_discovery_locked(nat, false); -clean_and_return: - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { - CONCURRENCY_LOCK(); - nfc_jni_reset_timeout_values(); - CONCURRENCY_UNLOCK(); -} - -static void setFelicaTimeout(jint timeout) { - // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. - // It can be set to 0 to disable the timeout altogether, in which case we - // use the sw watchdog as a fallback. - if (timeout <= 255) { - phLibNfc_SetFelicaTimeout(timeout); - } else { - // Disable hw timeout, use sw watchdog for timeout - phLibNfc_SetFelicaTimeout(0); - phLibNfc_SetHciTimeout(timeout); - } - -} -// Calculates ceiling log2 of value -static unsigned int log2(int value) { - unsigned int ret = 0; - bool isPowerOf2 = ((value & (value - 1)) == 0); - while ( (value >> ret) > 1 ) ret++; - if (!isPowerOf2) ret++; - return ret; -} - -// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X -// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X -// -// We keep the constant part of the formula in a static; note the factor -// 1000 off, which is due to the fact that the formula calculates seconds, -// but this method gets milliseconds as an argument. -static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; - -static int calcTimeout(int timeout_in_ms) { - // timeout = (256 * 16 / 13560000) * 2 ^ X - // First find the first X for which timeout > requested timeout - return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); -} - -static void setIsoDepTimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - // Then re-compute the actual timeout based on X - double actual_timeout = nxp_nfc_timeout_factor * (1 << value); - // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, - // but it will take some time to get back through the sw layers. - // 500 ms should be enough). - phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); - value |= 0x10; // bit 4 to enable timeout - phLibNfc_SetIsoXchgTimeout(value); - } - else { - // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout - // must be disabled completely, to prevent the PN544 from aborting - // the transaction. We reuse the HCI sw watchdog to catch the timeout - // in that case. - phLibNfc_SetIsoXchgTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static void setNfcATimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - phLibNfc_SetMifareRawTimeout(value); - } - else { - // Disable mifare raw timeout, use HCI sw watchdog instead - phLibNfc_SetMifareRawTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, - jint tech, jint timeout) { - bool success = false; - CONCURRENCY_LOCK(); - if (timeout <= 0) { - ALOGE("Timeout must be positive."); - return false; - } else { - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - setNfcATimeout(timeout); - success = true; - break; - case TARGET_TYPE_ISO14443_4: - setIsoDepTimeout(timeout); - success = true; - break; - case TARGET_TYPE_FELICA: - setFelicaTimeout(timeout); - success = true; - break; - default: - ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); - success = false; - } - } - CONCURRENCY_UNLOCK(); - return success; -} - -static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, - jint tech) { - int timeout = -1; - CONCURRENCY_LOCK(); - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - timeout = phLibNfc_GetMifareRawTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_ISO14443_4: - timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_FELICA: - timeout = phLibNfc_GetFelicaTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Felica timeout already in ms - } - break; - default: - ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); - break; - } - CONCURRENCY_UNLOCK(); - return timeout; -} - - -static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct nfc_jni_native_data *nat = NULL; - jclass cls; - jobject obj; - jfieldID f; - - TRACE("****** Init Native Structure ******"); - - /* Initialize native structure */ - nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); - if(nat == NULL) - { - ALOGD("malloc of nfc_jni_native_data failed"); - return FALSE; - } - memset(nat, 0, sizeof(*nat)); - e->GetJavaVM(&(nat->vm)); - nat->env_version = e->GetVersion(); - nat->manager = e->NewGlobalRef(o); - - cls = e->GetObjectClass(o); - f = e->GetFieldID(cls, "mNative", "I"); - e->SetIntField(o, f, (jint)nat); - - /* Initialize native cached references */ - cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); - - cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, - "notifyTransactionListeners", "([B)V"); - - cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, - "notifyTargetDeselected","()V"); - - cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, - "notifySeFieldActivated", "()V"); - - cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, - "notifySeFieldDeactivated", "()V"); - - cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, - "notifySeApduReceived", "([B)V"); - - cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, - "notifySeMifareAccess", "([B)V"); - - cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, - "notifySeEmvCardRemoval", "()V"); - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - TRACE("****** Init Native Structure OK ******"); - return TRUE; - -} - -/* Init/Deinit method */ -static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - int init_result = JNI_FALSE; -#ifdef TNFC_EMULATOR_ONLY - char value[PROPERTY_VALUE_MAX]; -#endif - jboolean result; - - CONCURRENCY_LOCK(); - -#ifdef TNFC_EMULATOR_ONLY - if (!property_get("ro.kernel.qemu", value, 0)) - { - ALOGE("NFC Initialization failed: not running in an emulator\n"); - goto clean_and_return; - } -#endif - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nat->seId = SMX_SECURE_ELEMENT_ID; - - nat->lto = 150; // LLCP_LTO - nat->miu = 128; // LLCP_MIU - // WKS indicates well-known services; 1 << sap for each supported SAP. - // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) - nat->wks = 0x13; // LLCP_WKS - nat->opt = 0; // LLCP_OPT - nat->p2p_initiator_modes = phNfc_eP2P_ALL; - nat->p2p_target_modes = 0x0E; // All passive except 106, active - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; - - nat->registry_info.MifareUL = TRUE; - nat->registry_info.MifareStd = TRUE; - nat->registry_info.ISO14443_4A = TRUE; - nat->registry_info.ISO14443_4B = TRUE; - nat->registry_info.Jewel = TRUE; - nat->registry_info.Felica = TRUE; - nat->registry_info.NFC = TRUE; - nat->registry_info.ISO15693 = TRUE; - - exported_nat = nat; - - /* Perform the initialization */ - init_result = nfc_jni_initialize(nat); - -clean_and_return: - CONCURRENCY_UNLOCK(); - - /* Convert the result and return */ - return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; -} - -static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) -{ - struct timespec ts; - NFCSTATUS status; - int result = JNI_FALSE; - struct nfc_jni_native_data *nat; - int bStackReset = FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Clear previous configuration */ - memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); - memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); - - /* Create the local semaphore */ - if (nfc_cb_data_init(&cb_data, NULL)) - { - TRACE("phLibNfc_Mgt_DeInitialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status == NFCSTATUS_PENDING) - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts) == -1) - { - ALOGW("Operation timed out"); - bStackReset = TRUE; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Failed to deinit the stack"); - bStackReset = TRUE; - } - } - else - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - bStackReset = TRUE; - } - nfc_cb_data_deinit(&cb_data); - } - else - { - ALOGE("Failed to create semaphore (errno=0x%08x)", errno); - bStackReset = TRUE; - } - - kill_client(nat); - - if(bStackReset == TRUE) - { - /* Complete deinit. failed, try hard restart of NFC */ - ALOGW("Reseting stack..."); - emergency_recovery(nat); - } - - result = nfc_jni_unconfigure_driver(nat); - - TRACE("NFC Deinitialized"); - - CONCURRENCY_UNLOCK(); - - return TRUE; -} - -/* Secure Element methods */ -static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { - NFCSTATUS ret; - jintArray list= NULL; - phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; - - TRACE("****** Get Secure Element List ******"); - - TRACE("phLibNfc_SE_GetSecureElementList()"); - REENTRANCE_LOCK(); - ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_SUCCESS) { - ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - return list; - } - TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - - TRACE("Nb SE: %d", se_count); - list =e->NewIntArray(se_count); - for (i = 0; i < se_count; i++) { - if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } - e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); - } - - e->DeleteLocalRef(list); - - return list; -} - -static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Select Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Virtual */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING) { - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Deselect Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Default */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, - nfc_jni_se_set_mode_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); - if (ret != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -/* Llcp methods */ - -static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - bool freeData = false; - jboolean result = JNI_FALSE; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data *cb_data; - - - CONCURRENCY_LOCK(); - - /* Memory allocation for cb_data - * This is on the heap because it is used by libnfc - * even after this call has succesfully finished. It is only freed - * upon link closure in nfc_jni_llcp_linkStatus_callback. - */ - cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(cb_data, (void*)nat)) - { - goto clean_and_return; - } - - /* Check LLCP compliancy */ - TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, - nfc_jni_checkLlcp_callback, - nfc_jni_llcp_linkStatus_callback, - (void*)cb_data); - REENTRANCE_UNLOCK(); - /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol - * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - freeData = true; - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data->sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data->status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(cb_data); - if (freeData) { - free(cb_data); - } - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Activate(hLlcpHandle); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_FALSE; - } -} - - - -static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, - jint nSap, jstring sn) -{ - NFCSTATUS ret; - jobject connectionlessSocket = NULL; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_native_data *nat; - phNfc_sData_t sWorkingBuffer = {NULL, 0}; - phNfc_sData_t serviceName = {NULL, 0}; - phLibNfc_Llcp_sLinkParameters_t sParams; - jclass clsNativeConnectionlessSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Allocate Working buffer length */ - phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); - sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, - NULL, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - - /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) - { - goto error; - } - - /* Get NativeConnectionless class object */ - clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); - if(e->ExceptionCheck()) - { - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); - e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); - TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); - - /* Set the miu link of the connectionless socket */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); - e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); - TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); - e->SetIntField(connectionlessSocket, f,(jint)nSap); - TRACE("Connectionless socket SAP = %d\n",nSap); - - return connectionlessSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - - if (sWorkingBuffer.buffer != NULL) { - free(sWorkingBuffer.buffer); - } - - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - phNfc_sData_t serviceName; - struct nfc_jni_native_data *nat; - jobject serviceSocket = NULL; - jclass clsNativeLlcpServiceSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - ret = phLibNfc_Llcp_Close(hLlcpSocket); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Listen( hLlcpSocket, - nfc_jni_llcp_transport_listen_socket_callback, - (void*)hLlcpSocket); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - /* Close created socket */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) - { - ALOGE("Llcp Socket object creation error"); - goto error; - } - - /* Get NativeLlcpServiceSocket class object */ - clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); - if(e->ExceptionCheck()) - { - ALOGE("Llcp Socket get object class error"); - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); - e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); - TRACE("Service socket Handle = %02x\n",hLlcpSocket); - - /* Set socket linear buffer length */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); - e->SetIntField(serviceSocket, f,(jint)linearBufferLength); - TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); - e->SetIntField(serviceSocket, f,(jint)miu); - TRACE("Service socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); - e->SetIntField(serviceSocket, f,(jint)rw); - TRACE("Service socket RW = %d\n",rw); - - return serviceSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) -{ - jobject clientSocket = NULL; - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - struct nfc_jni_native_data *nat; - jclass clsNativeLlcpSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - return NULL; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGE("Llcp socket object creation error"); - return NULL; - } - - /* Get NativeConnectionless class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGE("Get class object error"); - return NULL; - } - - /* Test if an SAP number is present */ - if(nSap != 0) - { - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - return NULL; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); - e->SetIntField(clientSocket, f,(jint)nSap); - TRACE("socket SAP = %d\n",nSap); - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hLlcpSocket); - TRACE("socket Handle = %02x\n",hLlcpSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - TRACE("socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - TRACE("socket RW = %d\n",rw); - - - return clientSocket; -} - -static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) -{ - TRACE("Last Error Status = 0x%02x",lastErrorStatus); - - if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) - { - return ERROR_BUFFER_TOO_SMALL; - } - else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) - { - return ERROR_INSUFFICIENT_RESOURCES; - } - else - { - return lastErrorStatus; - } -} - -static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) -{ - emergency_recovery(NULL); -} - -static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting init modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_initiator_modes = modes; -} - -static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting target modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_target_modes = modes; -} - -static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { - bool result = FALSE; - int load_result; - bool wasDisabled = FALSE; - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - NFCSTATUS status = NFCSTATUS_FAILED; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - result = FALSE; - goto clean_and_return; - } - - if (takeLock) - { - CONCURRENCY_LOCK(); - } - - /* Initialize Driver */ - if(!driverConfigured) - { - result = nfc_jni_configure_driver(nat); - wasDisabled = TRUE; - } - TRACE("com_android_nfc_NfcManager_doDownload()"); - - TRACE("Go in Download Mode"); - phLibNfc_Download_Mode(); - - TRACE("Load new Firmware Image"); - load_result = phLibNfc_Load_Firmware_Image(); - if(load_result != 0) - { - TRACE("Load new Firmware Image - status = %d",load_result); - result = FALSE; - goto clean_and_return; - } - - // Download - gInputParam.buffer = InputBuffer; - gInputParam.length = 0x01; - gOutputParam.buffer = OutputBuffer; - gOutputParam.length = 0x01; - - ALOGD("Download new Firmware"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - result = FALSE; - goto clean_and_return; - } - - /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we - try to download an old-style firmware on top of a new-style - firmware. Hence, this is expected behavior, and not an - error condition. */ - if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); - } - - /*Download is successful*/ - result = TRUE; -clean_and_return: - TRACE("phLibNfc_HW_Reset()"); - phLibNfc_HW_Reset(); - /* Deinitialize Driver */ - if(wasDisabled) - { - result = nfc_jni_unconfigure_driver(nat); - } - if (takeLock) - { - CONCURRENCY_UNLOCK(); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - return performDownload(nat, true); -} - -static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); - return e->NewStringUTF(buffer); -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doDownload", "()Z", - (void *)com_android_nfc_NfcManager_doDownload}, - - {"initializeNativeStructure", "()Z", - (void *)com_android_nfc_NfcManager_init_native_struc}, - - {"doInitialize", "()Z", - (void *)com_android_nfc_NfcManager_initialize}, - - {"doDeinitialize", "()Z", - (void *)com_android_nfc_NfcManager_deinitialize}, - - {"enableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_enableDiscovery}, - - {"doGetSecureElementList", "()[I", - (void *)com_android_nfc_NfcManager_doGetSecureElementList}, - - {"doSelectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doSelectSecureElement}, - - {"doDeselectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, - - {"doCheckLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doCheckLlcp}, - - {"doActivateLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doActivateLlcp}, - - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, - - {"doGetLastError", "()I", - (void *)com_android_nfc_NfcManager_doGetLastError}, - - {"disableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_disableDiscovery}, - - {"doSetTimeout", "(II)Z", - (void *)com_android_nfc_NfcManager_doSetTimeout}, - - {"doGetTimeout", "(I)I", - (void *)com_android_nfc_NfcManager_doGetTimeout}, - - {"doResetTimeouts", "()V", - (void *)com_android_nfc_NfcManager_doResetTimeouts}, - - {"doAbort", "()V", - (void *)com_android_nfc_NfcManager_doAbort}, - - {"doSetP2pInitiatorModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, - - {"doSetP2pTargetModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, - - {"doDump", "()Ljava/lang/String;", - (void *)com_android_nfc_NfcManager_doDump}, -}; - - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e) -{ - nfc_jni_native_monitor_t *nfc_jni_native_monitor; - - nfc_jni_native_monitor = nfc_jni_init_monitor(); - if(nfc_jni_native_monitor == NULL) - { - ALOGE("NFC Manager cannot recover native monitor %x\n", errno); - return -1; - } - - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", - gMethods, NELEM(gMethods)); -} - -} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp deleted file mode 100755 index bf0bffc..0000000 --- a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "com_android_nfc.h" - -static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; -static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; -static phNfc_sRemoteDevInformation_t* SecureElementInfo; -static int secureElementHandle; -extern void *gHWRef; -static int SecureElementTech; -extern uint8_t device_connected_flag; - -namespace android { - -static void com_android_nfc_jni_ioctl_callback ( void* pContext, - phNfc_sData_t* Outparam_Cb, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if (status == NFCSTATUS_SUCCESS ) - { - LOG_CALLBACK("> IOCTL successful",status); - } - else - { - LOG_CALLBACK("> IOCTL error",status); - } - - com_android_nfc_jni_ioctl_buffer = Outparam_Cb; - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); - - com_android_nfc_jni_transceive_buffer = pResBuffer; - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static void com_android_nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if(status==NFCSTATUS_SUCCESS) - { - LOG_CALLBACK("SE Set Mode is Successful",status); - TRACE("SE Handle: %lu", hSecureElement); - } - else - { - LOG_CALLBACK("SE Set Mode is failed\n ",status); - } - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - NFCSTATUS ret; - int i; - JNIEnv *e = nfc_get_env(); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); - } - else - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); - TRACE("Discovered %d secure elements", uNofRemoteDev); - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - bool foundHandle = false; - TRACE("Multiple Protocol supported\n"); - for (i=0; iRemDevType); - if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { - secureElementHandle = psRemoteDevList[i].hTargetDev; - foundHandle = true; - } - } - if (!foundHandle) { - ALOGE("Could not find ISO-DEP secure element"); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - } - else - { - secureElementHandle = psRemoteDevList->hTargetDev; - } - - TRACE("Secure Element Handle: 0x%08x", secureElementHandle); - - /* Set type name */ - jintArray techList; - nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); - - // TODO: Should use the "connected" technology, for now use the first - if ((techList != NULL) && e->GetArrayLength(techList) > 0) { - e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); - TRACE("Store Secure Element Info\n"); - SecureElementInfo = psRemoteDevList->psRemoteDevInfo; - - TRACE("Discovered secure element: tech=%d", SecureElementTech); - } - else { - ALOGE("Discovered secure element, but could not resolve tech"); - status = NFCSTATUS_FAILED; - } - - // This thread may not return to the virtual machine for a long time - // so make sure to delete the local refernce to the tech list. - e->DeleteLocalRef(techList); - } - -clean_and_return: - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - int semResult; - - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - uint8_t Output_Buff[10]; - uint8_t reg_value; - uint8_t mask_value; - struct nfc_jni_callback_data cb_data; - struct nfc_jni_callback_data cb_data_SE_Notification; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) - { - goto clean_and_return; - } - - /* Registery */ - registry_info.MifareUL = TRUE; - registry_info.MifareStd = TRUE; - registry_info.ISO14443_4A = TRUE; - registry_info.ISO14443_4B = TRUE; - registry_info.Jewel = TRUE; - registry_info.Felica = TRUE; - registry_info.NFC = FALSE; - - CONCURRENCY_LOCK(); - - TRACE("Open Secure Element"); - - /* Check if NFC device is already connected to a tag or P2P peer */ - if (device_connected_flag == 1) - { - ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); - goto clean_and_return; - } - - /* Test if External RF field is detected */ - InParam.buffer = ExternalRFDetected; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - /* Check the value */ - reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; - mask_value = reg_value & 0x40; - - if(mask_value == 0x40) - { - // There is an external RF field present, fail the open request - ALOGD("Unable to open SE connection, external RF Field detected"); - goto clean_and_return; - } - - /* Get Secure Element List */ - TRACE("phLibNfc_SE_GetSecureElementList()"); - ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); - if (ret == NFCSTATUS_SUCCESS) - { - TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i SMX detected"); - TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); - /* save SMARTMX index */ - SmartMX_detected = 1; - SmartMX_index = i; - } - } - - if(SmartMX_detected) - { - REENTRANCE_LOCK(); - TRACE("phLibNfc_RemoteDev_NtfRegister()"); - ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, - com_android_nfc_jni_open_secure_element_notification_callback, - (void *)&cb_data_SE_Notification); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("Register Notification error"); - goto clean_and_return; - } - - /* Set wired mode */ - REENTRANCE_LOCK(); - TRACE("phLibNfc_SE_SetMode: Wired mode"); - ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, - phLibNfc_SE_ActModeWired, - com_android_nfc_jni_smartMX_setModeCb, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING ) - { - ALOGE("\n> SE Set SmartMX mode ERROR \n" ); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("SE set mode failed"); - goto clean_and_return; - } - - TRACE("Waiting for notification"); - /* Wait for callback response */ - if(sem_wait(&cb_data_SE_Notification.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && - cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) - { - ALOGE("SE detection failed"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Connect Tag */ - CONCURRENCY_LOCK(); - TRACE("phLibNfc_RemoteDev_Connect(SMX)"); - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("CONNECT semaphore error"); - goto clean_and_return; - } - - /* Connect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Secure Element connect error"); - goto clean_and_return; - } - - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue | 0x40); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - /* Return the Handle of the SecureElement */ - return secureElementHandle; - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); - goto clean_and_return; - } - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - CONCURRENCY_UNLOCK(); - return 0; -} - - -static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) -{ - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - uint32_t SmartMX_Handle; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t Output_Buff[10]; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Close Secure element function "); - - CONCURRENCY_LOCK(); - /* Disconnect */ - TRACE("Disconnecting from SMX (handle = 0x%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, - NFC_SMARTMX_RELEASE, - com_android_nfc_jni_disconnect_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("\n> Disconnect SE ERROR \n" ); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue & 0xBF); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, - jobject o,jint handle, jbyteArray data) -{ - uint8_t offset = 0; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - - int tech = SecureElementTech; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Exchange APDU function "); - - CONCURRENCY_LOCK(); - - TRACE("Secure Element tech: %d\n", tech); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - /* Prepare transceive info structure */ - if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) - { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - else if(tech == TARGET_TYPE_ISO14443_4) - { - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - } - - transceive_info.sSendData.buffer = buf + offset; - transceive_info.sSendData.length = buflen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - com_android_nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("TRANSCEIVE semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("TRANSCEIVE error"); - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); - if(result != NULL) - { - e->SetByteArrayRegion(result, 0, - com_android_nfc_jni_transceive_buffer->length, - (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) -{ - TRACE("Get Secure element UID function "); - jbyteArray SecureElementUid; - - if(handle == secureElementHandle) - { - SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); - e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); - return SecureElementUid; - } - else - { - return NULL; - } -} - -static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) -{ - jintArray techList; - TRACE("Get Secure element Type function "); - - if(handle == secureElementHandle) - { - techList = e->NewIntArray(1); - e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); - return techList; - } - else - { - return NULL; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doNativeOpenSecureElementConnection", "()I", - (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, - {"doNativeDisconnectSecureElementConnection", "(I)Z", - (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, - {"doTransceive", "(I[B)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, - {"doGetUid", "(I)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, - {"doGetTechList", "(I)[I", - (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, -}; - -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp deleted file mode 100644 index dbf8dc9..0000000 --- a/nxp/jni/com_android_nfc_NativeNfcTag.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" -#include "phNfcHalTypes.h" - -static phLibNfc_Data_t nfc_jni_ndef_rw; -static phLibNfc_Handle handle; -uint8_t *nfc_jni_ndef_buf = NULL; -uint32_t nfc_jni_ndef_buf_len = 0; - -extern uint8_t device_connected_flag; - -namespace android { - -extern phLibNfc_Handle storedHandle; - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); -extern void nfc_jni_reset_timeout_values(); - -/* - * Callbacks - */ - static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_tag_rw_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - if (pCallbackData->pContext != NULL) { - // Store the remote dev info ptr in the callback context - // Note that this ptr will remain valid, it is tied to a statically - // allocated buffer in libnfc. - phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = - (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; - *ppRemoteDevInfo = psRemoteDevInfo; - } - - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_checkndef_callback(void *pContext, - phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_checkndef_callback", status); - phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); - if(status == NFCSTATUS_OK) - { - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; - nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); - if (pNdefInfo != NULL) *pNdefInfo = info; - } - else { - if (pNdefInfo != NULL) { - memset(pNdefInfo, 0, sizeof(*pNdefInfo)); - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_async_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; -} - -static phNfc_sData_t *nfc_jni_transceive_buffer; - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - nfc_jni_transceive_buffer = pResBuffer; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presencecheck_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_formatndef_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_readonly_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* Functions */ -static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, - jobject o) -{ - NFCSTATUS status; - phLibNfc_Handle handle = 0; - jbyteArray buf = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; - nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; - - TRACE("phLibNfc_Ndef_Read()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, - phLibNfc_Ndef_EBegin, - nfc_jni_tag_rw_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - buf = e->NewByteArray(nfc_jni_ndef_rw.length); - e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, - (jbyte *)nfc_jni_ndef_rw.buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - - return buf; -} - - -static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, - jobject o, jbyteArray buf) -{ - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); - nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_Ndef_Write()"); - TRACE("Ndef Handle :0x%x\n",handle); - TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * Utility to recover poll bytes from target infos - */ -static void set_target_pollBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); - - jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingPollBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - jint *techId = e->GetIntArrayElements(techList, 0); - int techListLength = e->GetArrayLength(techList); - - jbyteArray pollBytes = e->NewByteArray(0); - jobjectArray techPollBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(pollBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) - { - /* ISO14443-3A: ATQA/SENS_RES */ - case TARGET_TYPE_ISO14443_3A: - if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { - // Jewel ATQA is not read and stored by the PN544, but it is fixed - // at {0x00, 0x0C} in the spec. So eJewel can safely be - // translated to {0x00, 0x0C}. - const static jbyte JewelAtqA[2] = {0x00, 0x0C}; - pollBytes = e->NewByteArray(2); - e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); - } - else { - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); - } - break; - /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ - case TARGET_TYPE_ISO14443_3B: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); - break; - /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ - case TARGET_TYPE_FELICA: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - pollBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techPollBytes, tech, pollBytes); - } - - e->SetObjectField(tag, f, techPollBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); - -} - -/* - * Utility to recover activation bytes from target infos - */ -static void set_target_activationBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - - jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); - jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingActBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - int techListLength = e->GetArrayLength(techList); - jint *techId = e->GetIntArrayElements(techList, 0); - - jbyteArray actBytes = e->NewByteArray(0); - jobjectArray techActBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(actBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) { - - /* ISO14443-3A: SAK/SEL_RES */ - case TARGET_TYPE_ISO14443_3A: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); - break; - /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ - /* ISO14443-3B & ISO14443-4: HiLayerResp */ - case TARGET_TYPE_ISO14443_4: - // Determine whether -A or -B - if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); - e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); - } - else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); - e->SetByteArrayRegion(actBytes, 0, - psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); - } - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - actBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techActBytes, tech, actBytes); - } - e->SetObjectField(tag, f, techActBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); -} - -static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - // Success, set poll & act bytes - set_target_pollBytes(e, o, pRemDevInfo); - set_target_activationBytes(e, o, pRemDevInfo); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, - jobject o) -{ - // Reconnect is provided by libnfc by just calling connect again - // on the same handle. - int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - if (libNfcType != -1) { - // Note that some tag types are stateless, hence we do not reconnect - // those. Currently those are the Jewel and Iso15693 technologies. - if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); - return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); - } - else { - return NFCSTATUS_SUCCESS; - } - } - else { - return NFCSTATUS_REJECTED; - } -} - - -static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_connected_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Reset the stored handle */ - storedHandle = 0; - - nfc_jni_reset_timeout_values(); - - /* Disconnect */ - TRACE("Disconnecting from tag (%x)", handle); - - if (handle == -1) { - // Was never connected to any tag, exit - result = JNI_TRUE; - ALOGE("doDisconnect() - Target already disconnected"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, - nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - result = JNI_TRUE; - TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); - goto clean_and_return; - } - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static uint16_t -crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) -{ - uint16_t b, crc = init; - - do { - b = *msg++ ^ (crc & 0xFF); - b ^= (b << 4) & 0xFF; - crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); - } while( --len ); - - return crc; -} - -static void -nfc_insert_crc_a( uint8_t* msg, size_t len ) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - msg[len] = crc & 0xFF; - msg[len + 1] = (crc >> 8) & 0xFF; -} - -static void -nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - *byte1 = crc & 0xFF; - *byte2 = (crc >> 8) & 0xFF; -} - -static bool -crc_valid( uint8_t* msg, size_t len) -{ - uint8_t crcByte1, crcByte2; - - nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, - len - 2, &crcByte1, &crcByte2); - - if (msg[len - 2] == crcByte1 && - msg[len - 1] == crcByte2) { - return true; - } - else { - return false; - } - -} - -static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, - jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) -{ - uint8_t offset = 0; - // buf is the pointer to the JNI array and never overwritten, - // outbuf is passed into the transceive - it may be pointed to new memory - // to be extended with CRC. - uint8_t *buf = NULL; - uint32_t buflen; - - uint8_t *outbuf = NULL; - uint32_t outlen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - int selectedTech = 0; - int selectedLibNfcType = 0; - jint* technologies = NULL; - bool checkResponseCrc = false; - - jint *targetLost; - if (statusTargetLost != NULL) { - targetLost = e->GetIntArrayElements(statusTargetLost, 0); - if (targetLost != NULL) { - *targetLost = 0; - } - } else { - targetLost = NULL; - } - - memset(&transceive_info, 0, sizeof(transceive_info)); - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - selectedTech = nfc_jni_get_connected_technology(e, o); - selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - - buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = outlen = (uint32_t)e->GetArrayLength(data); - - switch (selectedTech) { - case TARGET_TYPE_FELICA: - transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - if (raw) { - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - break; - case TARGET_TYPE_ISO14443_3A: - // Check which libnfc type - if (selectedLibNfcType == phNfc_eJewel_PICC) { - // For the Jewel pipe, CRC is automatically computed - transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; - transceive_info.addr = 0; - } else { - if (raw) { - // Use Mifare Raw to implement a standard - // ISO14443-3A transceive, with CRC added - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - // Use the mifare pipe - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - - } - break; - case TARGET_TYPE_ISO14443_4: - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_ISO15693: - transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; - transceive_info.addr = 0; - break; - case TARGET_TYPE_UNKNOWN: - case TARGET_TYPE_ISO14443_3B: - // Not supported - goto clean_and_return; - default: - break; - } - - transceive_info.sSendData.buffer = outbuf + offset; - transceive_info.sSendData.length = outlen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - - /* Copy results back to Java * - * In case of NfcA and raw, also check the CRC in the response - * and cut it off in the returned data. - */ - if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { - if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { - result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length - 2, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } - } else { - result = e->NewByteArray(nfc_jni_transceive_buffer->length); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - if ((outbuf != buf) && (outbuf != NULL)) { - // Buf was extended and re-alloced with crc bytes, free separately - free(outbuf); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)buf, JNI_ABORT); - - if (targetLost != NULL) { - e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); - } - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, - jint libnfcType, jint javaType) -{ - jint ndefType = NDEF_UNKNOWN_TYPE; - - switch (libnfcType) { - case phNfc_eJewel_PICC: - ndefType = NDEF_TYPE1_TAG; - break; - case phNfc_eISO14443_3A_PICC: - ndefType = NDEF_TYPE2_TAG;; - break; - case phNfc_eFelica_PICC: - ndefType = NDEF_TYPE3_TAG; - break; - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - ndefType = NDEF_TYPE4_TAG; - break; - case phNfc_eMifare_PICC: - if (javaType == TARGET_TYPE_MIFARE_UL) { - ndefType = NDEF_TYPE2_TAG; - } else { - ndefType = NDEF_MIFARE_CLASSIC_TAG; - } - break; - case phNfc_eISO15693_PICC: - ndefType = NDEF_ICODE_SLI_TAG; - break; - default: - ndefType = NDEF_UNKNOWN_TYPE; - break; - } - return ndefType; -} - -static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) -{ - phLibNfc_Handle handle = 0; - jint status; - phLibNfc_ChkNdef_Info_t sNdefInfo; - struct nfc_jni_callback_data cb_data; - jint *ndef = e->GetIntArrayElements(ndefinfo, 0); - int apiCardState = NDEF_MODE_UNKNOWN; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - cb_data.pContext = &sNdefInfo; - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_Ndef_CheckNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); - - if (status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ndef[0] = sNdefInfo.MaxNdefMsgLength; - // Translate the card state to know values for the NFC API - switch (sNdefInfo.NdefCardState) { - case PHLIBNFC_NDEF_CARD_INITIALISED: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_READ_ONLY: - apiCardState = NDEF_MODE_READ_ONLY; - break; - case PHLIBNFC_NDEF_CARD_READ_WRITE: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_INVALID: - apiCardState = NDEF_MODE_UNKNOWN; - break; - } - ndef[1] = apiCardState; - -clean_and_return: - e->ReleaseIntArrayElements(ndefinfo, ndef, 0); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_RemoteDev_CheckPresence()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, - jobject o, jbyteArray pollBytes, jbyteArray actBytes) -{ - // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire - // is supported. - jboolean result = JNI_FALSE; - - // DESfire has one sak byte and 2 ATQA bytes - if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && - actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { - jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); - jbyte* act = e->GetByteArrayElements(actBytes, NULL); - if (act[0] == 0x20 && poll[1] == 0x03) { - uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; - // Identifies as DESfire, use get version cmd to be sure - jbyteArray versionCmd = e->NewByteArray(5); - e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); - jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, - versionCmd, JNI_TRUE, NULL); - if (respBytes != NULL) { - // Check whether the response matches a typical DESfire - // response. - // libNFC even does more advanced checking than we do - // here, and will only format DESfire's with a certain - // major/minor sw version and NXP as a manufacturer. - // We don't want to do such checking here, to avoid - // having to change code in multiple places. - // A succesful (wrapped) DESFire getVersion command returns - // 9 bytes, with byte 7 0x91 and byte 8 having status - // code 0xAF (these values are fixed and well-known). - int respLength = e->GetArrayLength(respBytes); - jbyte* resp = e->GetByteArrayElements(respBytes, NULL); - if (respLength == 9 && resp[7] == (jbyte)0x91 && - resp[8] == (jbyte)0xAF) { - result = JNI_TRUE; - } - e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); - } - } - e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); - e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); - } - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - phNfc_sData_t keyBuffer; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_RemoteDev_FormatNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t keyBuffer; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_ConvertToReadOnlyNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeNfcTag_doDisconnect}, - {"doReconnect", "()I", - (void *)com_android_nfc_NativeNfcTag_doReconnect}, - {"doHandleReconnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, - {"doTransceive", "([BZ[I)[B", - (void *)com_android_nfc_NativeNfcTag_doTransceive}, - {"doGetNdefType", "(II)I", - (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, - {"doCheckNdef", "([I)I", - (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, - {"doRead", "()[B", - (void *)com_android_nfc_NativeNfcTag_doRead}, - {"doWrite", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doWrite}, - {"doPresenceCheck", "()Z", - (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, - {"doIsIsoDepNdefFormatable", "([B[B)Z", - (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, - {"doNdefFormat", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, - {"doMakeReadonly", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, -}; - -int register_com_android_nfc_NativeNfcTag(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp deleted file mode 100644 index b3cc6e3..0000000 --- a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp +++ /dev/null @@ -1,490 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -extern uint8_t device_connected_flag; - -namespace android { - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); - -/* - * Callbacks - */ -static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presence_check_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; - psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_receive_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - *ptr = data; - } - else - { - *ptr = NULL; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Functions - */ - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - /* Report the callback data and wake up the caller */ - pCallbackData->pContext = pResBuffer; - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - jclass target_cls = NULL; - jobject tag; - jmethodID ctor; - jfieldID f; - jbyteArray generalBytes = NULL; - phNfc_sData_t sGeneralBytes; - unsigned int i; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Set General Bytes */ - target_cls = e->GetObjectClass(o); - - f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes Length = %d", sGeneralBytes.length); - TRACE("General Bytes ="); - for(i=0;iNewByteArray(sGeneralBytes.length); - - e->SetByteArrayRegion(generalBytes, 0, - sGeneralBytes.length, - (jbyte *)sGeneralBytes.buffer); - - e->SetObjectField(o, f, generalBytes); - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - /* Restart the polling loop if the connection failed */ - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jboolean result = JNI_FALSE; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Disconnect */ - TRACE("Disconnecting from target (handle = 0x%x)", handle); - - /* NativeNfcTag waits for tag to leave the field here with presence check. - * We do not in P2P path because presence check is not safe while transceive may be - * in progress. - */ - - TRACE("phLibNfc_RemoteDev_Disconnect()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); - } - else - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, - jobject o, jbyteArray data) -{ - NFCSTATUS status; - uint8_t offset = 2; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - phNfc_sData_t * receive_buffer = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) - { - goto clean_and_return; - } - - /* Transceive*/ - TRACE("Transceive data to target (handle = 0x%x)", handle); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - TRACE("Buffer Length = %d\n", buflen); - - transceive_info.sSendData.buffer = buf; //+ offset; - transceive_info.sSendData.length = buflen; //- offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(receive_buffer->length); - if(result != NULL) - e->SetByteArrayRegion(result, 0, - receive_buffer->length, - (jbyte *)receive_buffer->buffer); - -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - - -static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( - JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct timespec ts; - phLibNfc_Handle handle; - jbyteArray buf = NULL; - static phNfc_sData_t *data; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)data)) - { - goto clean_and_return; - } - - /* Receive */ - TRACE("phLibNfc_RemoteDev_Receive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(data == NULL) - { - goto clean_and_return; - } - - buf = e->NewByteArray(data->length); - e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return buf; -} - -static jboolean com_android_nfc_NativeP2pDevice_doSend( - JNIEnv *e, jobject o, jbyteArray buf) -{ - NFCSTATUS status; - phNfc_sData_t data; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Send */ - TRACE("Send data to the Initiator (handle = 0x%x)", handle); - - data.length = (uint32_t)e->GetArrayLength(buf); - data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_RemoteDev_Send()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, - {"doTransceive", "([B)[B", - (void *)com_android_nfc_NativeP2pDevice_doTransceive}, - {"doReceive", "()[B", - (void *)com_android_nfc_NativeP2pDevice_doReceive}, - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeP2pDevice_doSend}, -}; - -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", - gMethods, NELEM(gMethods)); -} - -} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp deleted file mode 100644 index f0487d3..0000000 --- a/nxp/jni/com_android_nfc_list.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#undef LOG_TAG -#define LOG_TAG "NFC_LIST" - -bool listInit(listHead* pList) -{ - pList->pFirst = NULL; - if(pthread_mutex_init(&pList->mutex, NULL) == -1) - { - ALOGE("Mutex creation failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listDestroy(listHead* pList) -{ - bool bListNotEmpty = true; - while (bListNotEmpty) { - bListNotEmpty = listGetAndRemoveNext(pList, NULL); - } - - if(pthread_mutex_destroy(&pList->mutex) == -1) - { - ALOGE("Mutex destruction failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listAdd(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pLastNode; - bool result; - - /* Create node */ - pNode = (struct listNode*)malloc(sizeof(listNode)); - if (pNode == NULL) - { - result = false; - ALOGE("Failed to malloc"); - goto clean_and_return; - } - TRACE("Allocated node: %8p (%8p)", pNode, pData); - pNode->pData = pData; - pNode->pNext = NULL; - - pthread_mutex_lock(&pList->mutex); - - /* Add the node to the list */ - if (pList->pFirst == NULL) - { - /* Set the node as the head */ - pList->pFirst = pNode; - } - else - { - /* Seek to the end of the list */ - pLastNode = pList->pFirst; - while(pLastNode->pNext != NULL) - { - pLastNode = pLastNode->pNext; - } - - /* Add the node to the current list */ - pLastNode->pNext = pNode; - } - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listRemove(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pRemovedNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst == NULL) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - pNode = pList->pFirst; - if (pList->pFirst->pData == pData) - { - /* Get the removed node */ - pRemovedNode = pNode; - - /* Remove the first node */ - pList->pFirst = pList->pFirst->pNext; - } - else - { - while (pNode->pNext != NULL) - { - if (pNode->pNext->pData == pData) - { - /* Node found ! */ - break; - } - pNode = pNode->pNext; - } - - if (pNode->pNext == NULL) - { - /* Node not found */ - result = false; - ALOGE("Failed to deallocate (not found %8p)", pData); - goto clean_and_return; - } - - /* Get the removed node */ - pRemovedNode = pNode->pNext; - - /* Remove the node from the list */ - pNode->pNext = pNode->pNext->pNext; - } - - /* Deallocate the node */ - TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); - free(pRemovedNode); - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listGetAndRemoveNext(listHead* pList, void** ppData) -{ - struct listNode* pNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - /* Work on the first node */ - pNode = pList->pFirst; - - /* Return the data */ - if (ppData != NULL) - { - *ppData = pNode->pData; - } - - /* Remove and deallocate the node */ - pList->pFirst = pNode->pNext; - TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); - free(pNode); - - result = true; - -clean_and_return: - listDump(pList); - pthread_mutex_unlock(&pList->mutex); - return result; -} - -void listDump(listHead* pList) -{ - struct listNode* pNode = pList->pFirst; - - TRACE("Node dump:"); - while (pNode != NULL) - { - TRACE("- %8p (%8p)", pNode, pNode->pData); - pNode = pNode->pNext; - } -} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h deleted file mode 100644 index 22b4f09..0000000 --- a/nxp/jni/com_android_nfc_list.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_LIST_H__ -#define __COM_ANDROID_NFC_LIST_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct listNode -{ - void* pData; - struct listNode* pNext; -}; - -struct listHead -{ - listNode* pFirst; - pthread_mutex_t mutex; -}; - -bool listInit(listHead* pList); -bool listDestroy(listHead* pList); -bool listAdd(listHead* pList, void* pData); -bool listRemove(listHead* pList, void* pData); -bool listGetAndRemoveNext(listHead* pList, void** ppData); -void listDump(listHead* pList); - -#ifdef __cplusplus -} -#endif - -#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index db78496..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java deleted file mode 100755 index 3a7e57f..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java deleted file mode 100755 index 69506c5..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java deleted file mode 100755 index f969627..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java deleted file mode 100755 index e2d91ec..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java deleted file mode 100755 index eddde94..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java deleted file mode 100755 index 094f46a..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 3e7a6b5..602b25d 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.dhimpl.NativeNfcManager; -import com.android.nfc.dhimpl.NativeNfcSecureElement; +import com.android.nfc.nxp.NativeNfcManager; +import com.android.nfc.nxp.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; diff --git a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..c9d3b5d --- /dev/null +++ b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..531afd8 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java new file mode 100755 index 0000000..a337d35 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java new file mode 100755 index 0000000..4bd8c24 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java new file mode 100755 index 0000000..88f9b9d --- /dev/null +++ b/src/com/android/nfc/nxp/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java new file mode 100755 index 0000000..8996dfb --- /dev/null +++ b/src/com/android/nfc/nxp/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java new file mode 100755 index 0000000..7c7db41 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} -- cgit v1.1 From 4bbd47e5507d4c47a4d722216606307e45195a0a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 25 Jul 2012 08:56:11 -0700 Subject: Move NXP JNI and DeviceHost implementation into separate dir. Preparation for the new NCI stack. The idea is to build either the NXP or the NCI stack, triggered by a makefile switch. To that end, move the DeviceHost and JNI implementations in their own directory, so we can build them only if needed. Change-Id: I8579ec30ceb1908e4cd180cfbd10224aa4bddb8d --- Android.mk | 8 + jni/Android.mk | 35 - jni/com_android_nfc.cpp | 564 ----- jni/com_android_nfc.h | 261 -- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 -- jni/com_android_nfc_NativeLlcpServiceSocket.cpp | 227 -- jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ---- jni/com_android_nfc_NativeNfcManager.cpp | 2623 -------------------- jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ------ jni/com_android_nfc_NativeNfcTag.cpp | 1255 ---------- jni/com_android_nfc_NativeP2pDevice.cpp | 490 ---- jni/com_android_nfc_list.cpp | 210 -- jni/com_android_nfc_list.h | 49 - nxp/Android.mk | 3 + nxp/jni/Android.mk | 35 + nxp/jni/com_android_nfc.cpp | 564 +++++ nxp/jni/com_android_nfc.h | 261 ++ ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 ++ .../com_android_nfc_NativeLlcpServiceSocket.cpp | 227 ++ nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ++++ nxp/jni/com_android_nfc_NativeNfcManager.cpp | 2623 ++++++++++++++++++++ nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ++++++ nxp/jni/com_android_nfc_NativeNfcTag.cpp | 1255 ++++++++++ nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 490 ++++ nxp/jni/com_android_nfc_list.cpp | 210 ++ nxp/jni/com_android_nfc_list.h | 49 + .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 + .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 + .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 373 +++ .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 + nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 803 ++++++ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 + src/com/android/nfc/NfcService.java | 4 +- .../nfc/nxp/NativeLlcpConnectionlessSocket.java | 78 - .../android/nfc/nxp/NativeLlcpServiceSocket.java | 53 - src/com/android/nfc/nxp/NativeLlcpSocket.java | 99 - src/com/android/nfc/nxp/NativeNfcManager.java | 373 --- .../android/nfc/nxp/NativeNfcSecureElement.java | 67 - src/com/android/nfc/nxp/NativeNfcTag.java | 803 ------ src/com/android/nfc/nxp/NativeP2pDevice.java | 77 - 41 files changed, 8768 insertions(+), 8757 deletions(-) delete mode 100644 jni/Android.mk delete mode 100644 jni/com_android_nfc.cpp delete mode 100644 jni/com_android_nfc.h delete mode 100644 jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpServiceSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpSocket.cpp delete mode 100644 jni/com_android_nfc_NativeNfcManager.cpp delete mode 100755 jni/com_android_nfc_NativeNfcSecureElement.cpp delete mode 100644 jni/com_android_nfc_NativeNfcTag.cpp delete mode 100644 jni/com_android_nfc_NativeP2pDevice.cpp delete mode 100644 jni/com_android_nfc_list.cpp delete mode 100644 jni/com_android_nfc_list.h create mode 100644 nxp/Android.mk create mode 100644 nxp/jni/Android.mk create mode 100644 nxp/jni/com_android_nfc.cpp create mode 100644 nxp/jni/com_android_nfc.h create mode 100644 nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcManager.cpp create mode 100755 nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcTag.cpp create mode 100644 nxp/jni/com_android_nfc_NativeP2pDevice.cpp create mode 100644 nxp/jni/com_android_nfc_list.cpp create mode 100644 nxp/jni/com_android_nfc_list.h create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpServiceSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcManager.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcSecureElement.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcTag.java delete mode 100755 src/com/android/nfc/nxp/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index a041854..2cdfc68 100644 --- a/Android.mk +++ b/Android.mk @@ -6,6 +6,14 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) +ifeq ($(NFC_USE_NCI_STACK), true) + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nci) +else + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nxp) +endif + LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform diff --git a/jni/Android.mk b/jni/Android.mk deleted file mode 100644 index 8ae792a..0000000 --- a/jni/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES:= \ - com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ - com_android_nfc_NativeLlcpServiceSocket.cpp \ - com_android_nfc_NativeLlcpSocket.cpp \ - com_android_nfc_NativeNfcManager.cpp \ - com_android_nfc_NativeNfcTag.cpp \ - com_android_nfc_NativeP2pDevice.cpp \ - com_android_nfc_NativeNfcSecureElement.cpp \ - com_android_nfc_list.cpp \ - com_android_nfc.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/libnfc-nxp/src \ - external/libnfc-nxp/inc - -LOCAL_SHARED_LIBRARIES := \ - libnativehelper \ - libcutils \ - libutils \ - libnfc \ - libhardware - -#LOCAL_CFLAGS += -O0 -g - -LOCAL_MODULE := libnfc_jni -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp deleted file mode 100644 index d794d6e..0000000 --- a/jni/com_android_nfc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "errno.h" -#include "com_android_nfc.h" -#include "com_android_nfc_list.h" -#include "phLibNfcStatus.h" - -/* - * JNI Initialization - */ -jint JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - JNIEnv *e; - - ALOGD("NFC Service : loading JNI\n"); - - // Check JNI version - if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) - return JNI_ERR; - - android::vm = jvm; - - if (android::register_com_android_nfc_NativeNfcManager(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcTag(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) - return JNI_ERR; - - return JNI_VERSION_1_6; -} - -namespace android { - -extern struct nfc_jni_native_data *exported_nat; - -JavaVM *vm; - -/* - * JNI Utils - */ -JNIEnv *nfc_get_env() -{ - JNIEnv *e; - if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Current thread is not attached to VM"); - phLibNfc_Mgt_Recovery(); - abort(); - } - return e; -} - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) -{ - /* Create semaphore */ - if(sem_init(&pCallbackData->sem, 0, 0) == -1) - { - ALOGE("Semaphore creation failed (errno=0x%08x)", errno); - return false; - } - - /* Set default status value */ - pCallbackData->status = NFCSTATUS_FAILED; - - /* Copy the context */ - pCallbackData->pContext = pContext; - - /* Add to active semaphore list */ - if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to add the semaphore to the list"); - } - - return true; -} - -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) -{ - /* Destroy semaphore */ - if (sem_destroy(&pCallbackData->sem)) - { - ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); - } - - /* Remove from active semaphore list */ - if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to remove semaphore from the list"); - } - -} - -void nfc_cb_data_releaseAll() -{ - nfc_jni_callback_data* pCallbackData; - - while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) - { - pCallbackData->status = NFCSTATUS_FAILED; - sem_post(&pCallbackData->sem); - } -} - -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj) -{ - jclass cls; - jobject obj; - jmethodID ctor; - - cls = e->FindClass(clsname); - if(cls == NULL) - { - return -1; - ALOGD("Find class error\n"); - } - - - ctor = e->GetMethodID(cls, "", "()V"); - - obj = e->NewObject(cls, ctor); - if(obj == NULL) - { - return -1; - ALOGD("Create object error\n"); - } - - *cached_obj = e->NewGlobalRef(obj); - if(*cached_obj == NULL) - { - e->DeleteLocalRef(obj); - ALOGD("Global ref error\n"); - return -1; - } - - e->DeleteLocalRef(obj); - - return 0; -} - - -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - /* Retrieve native structure address */ - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mNative", "I"); - return (struct nfc_jni_native_data*)e->GetIntField(o, f); -} - -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) -{ - return exported_nat; -} - -static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; - -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) -{ - - pthread_mutexattr_t recursive_attr; - - pthread_mutexattr_init(&recursive_attr); - pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); - - if(nfc_jni_native_monitor == NULL) - { - nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); - } - - if(nfc_jni_native_monitor != NULL) - { - memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); - - if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) - { - ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) - { - ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(!listInit(&nfc_jni_native_monitor->sem_list)) - { - ALOGE("NFC Manager Semaphore List creation failed"); - return NULL; - } - - LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); - - if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) - { - ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) - { - ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); - return NULL; - } - -} - - return nfc_jni_native_monitor; -} - -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) -{ - return nfc_jni_native_monitor; -} - - -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mMode", "S"); - - return e->GetShortField(o, f); -} - - -int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) -{ - - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedTechIndex", "I"); - - return e->GetIntField(o, f); - -} - -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - int connectedTech = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); - - if ((connectedTechIndex != -1) && (techTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(techTypes))) { - jint* technologies = e->GetIntArrayElements(techTypes, 0); - if (technologies != NULL) { - connectedTech = technologies[connectedTechIndex]; - e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); - } - } - - return connectedTech; - -} - -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jint connectedLibNfcType = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); - jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); - - if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { - jint* types = e->GetIntArrayElements(libNfcTypes, 0); - if (types != NULL) { - connectedLibNfcType = types[connectedTechIndex]; - e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); - } - } - return connectedLibNfcType; - -} - -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedHandle", "I"); - - return e->GetIntField(o, f); -} - -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jintArray techtypes; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechList","[I"); - - /* Read the techtypes */ - techtypes = (jintArray) e->GetObjectField(o, f); - - return techtypes; -} - - - -//Display status code -const char* nfc_jni_get_status_name(NFCSTATUS status) -{ - #define STATUS_ENTRY(status) { status, #status } - - struct status_entry { - NFCSTATUS code; - const char *name; - }; - - const struct status_entry sNameTable[] = { - STATUS_ENTRY(NFCSTATUS_SUCCESS), - STATUS_ENTRY(NFCSTATUS_FAILED), - STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), - STATUS_ENTRY(NFCSTATUS_TARGET_LOST), - STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), - STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), - STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_SHUTDOWN), - STATUS_ENTRY(NFCSTATUS_ABORTED), - STATUS_ENTRY(NFCSTATUS_REJECTED ), - STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), - STATUS_ENTRY(NFCSTATUS_PENDING), - STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), - STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), - STATUS_ENTRY(NFCSTATUS_BUSY), - STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), - STATUS_ENTRY(NFCSTATUS_DESELECTED), - STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), - STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), - STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), - STATUS_ENTRY(NFCSTATUS_RF_ERROR), - STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), - STATUS_ENTRY(NFCSTATUS_INVALID_STATE), - STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), - STATUS_ENTRY(NFCSTATUS_RELEASED), - STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), - STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), - STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_READ_FAILED), - STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), - STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), - STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), - STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), - STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), - STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), - }; - - int i = sizeof(sNameTable)/sizeof(status_entry); - - while(i>0) - { - i--; - if (sNameTable[i].code == PHNFCSTATUS(status)) - { - return sNameTable[i].name; - } - } - - return "UNKNOWN"; -} - -int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, - int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { - bool found = false; - for (int i = 0; i < listSize; i++) { - if (techList[i] == techToAdd) { - found = true; - break; - } - } - if (!found && listSize < maxListSize) { - techList[listSize] = techToAdd; - handleList[listSize] = handleToAdd; - typeList[listSize] = typeToAdd; - return listSize + 1; - } - else { - return listSize; - } -} - - -#define MAX_NUM_TECHNOLOGIES 32 - -/* - * Utility to get a technology tree and a corresponding handle list from a detected tag. - */ -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* libnfcTypeList) -{ - int technologies[MAX_NUM_TECHNOLOGIES]; - int handles[MAX_NUM_TECHNOLOGIES]; - int libnfctypes[MAX_NUM_TECHNOLOGIES]; - - int index = 0; - // TODO: This counts from up to down because on multi-protocols, the - // ISO handle is usually the second, and we prefer the ISO. Should implement - // a method to find the "preferred handle order" and use that instead, - // since we shouldn't have dependencies on the tech list ordering. - for (int target = count - 1; target >= 0; target--) { - int type = devList[target].psRemoteDevInfo->RemDevType; - int handle = devList[target].hTargetDev; - switch (type) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - break; - } - case phNfc_eISO14443_4B_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO14443_3A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - case phNfc_eISO14443_B_PICC: - { - // TODO a bug in libnfc will cause 14443-3B only cards - // to be returned as this type as well, but these cards - // are very rare. Hence assume it's -4B - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO15693_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); - }break; - case phNfc_eMifare_PICC: - { - // We don't want to be too clever here; libnfc has already determined - // it's a Mifare, so we only check for UL, for all other tags - // we assume it's a mifare classic. This should make us more - // future-proof. - int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; - switch(sak) - { - case 0x00: - // could be UL or UL-C - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); - break; - default: - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); - break; - } - }break; - case phNfc_eFelica_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); - }break; - case phNfc_eJewel_PICC: - { - // Jewel represented as NfcA - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - default: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); - } - } - } - - // Build the Java arrays - if (techList != NULL) { - *techList = e->NewIntArray(index); - e->SetIntArrayRegion(*techList, 0, index, technologies); - } - - if (handleList != NULL) { - *handleList = e->NewIntArray(index); - e->SetIntArrayRegion(*handleList, 0, index, handles); - } - - if (libnfcTypeList != NULL) { - *libnfcTypeList = e->NewIntArray(index); - e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); - } -} - -} // namespace android diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h deleted file mode 100644 index b876dad..0000000 --- a/jni/com_android_nfc.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_JNI_H__ -#define __COM_ANDROID_NFC_JNI_H__ - -#define LOG_TAG "NFCJNI" - -#include -#include - -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include - -} -#include // for property_get - - -/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ -#define DISCOVERY_MODE_TAG_READER 0 -#define DISCOVERY_MODE_NFCIP1 1 -#define DISCOVERY_MODE_CARD_EMULATION 2 - -#define DISCOVERY_MODE_TABLE_SIZE 3 - -#define DISCOVERY_MODE_DISABLED 0 -#define DISCOVERY_MODE_ENABLED 1 - -#define MODE_P2P_TARGET 0 -#define MODE_P2P_INITIATOR 1 - -/* Properties values */ -#define PROPERTY_LLCP_LTO 0 -#define PROPERTY_LLCP_MIU 1 -#define PROPERTY_LLCP_WKS 2 -#define PROPERTY_LLCP_OPT 3 -#define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 -#define PROPERTY_NFC_DISCOVERY_F 6 -#define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 - -/* Error codes */ -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -/* Pre-defined card read/write state values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_UNKNOWN_TYPE -1 -#define NDEF_TYPE1_TAG 1 -#define NDEF_TYPE2_TAG 2 -#define NDEF_TYPE3_TAG 3 -#define NDEF_TYPE4_TAG 4 -#define NDEF_MIFARE_CLASSIC_TAG 101 -#define NDEF_ICODE_SLI_TAG 102 - -/* Pre-defined tag type values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_MODE_READ_ONLY 1 -#define NDEF_MODE_READ_WRITE 2 -#define NDEF_MODE_UNKNOWN 3 - - -/* Name strings for target types. These *must* match the values in TagTechnology.java */ -#define TARGET_TYPE_UNKNOWN -1 -#define TARGET_TYPE_ISO14443_3A 1 -#define TARGET_TYPE_ISO14443_3B 2 -#define TARGET_TYPE_ISO14443_4 3 -#define TARGET_TYPE_FELICA 4 -#define TARGET_TYPE_ISO15693 5 -#define TARGET_TYPE_NDEF 6 -#define TARGET_TYPE_NDEF_FORMATABLE 7 -#define TARGET_TYPE_MIFARE_CLASSIC 8 -#define TARGET_TYPE_MIFARE_UL 9 - -#define SMX_SECURE_ELEMENT_ID 11259375 - -/* Maximum byte length of an AID. */ -#define AID_MAXLEN 16 - -/* Utility macros for logging */ -#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN - -#if 0 - #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); - #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) - #define TRACE_ENABLED 1 -#else - #define LOG_CALLBACK(...) - #define TRACE(...) - #define TRACE_ENABLED 0 -#endif - -struct nfc_jni_native_data -{ - /* Thread handle */ - pthread_t thread; - int running; - - /* Our VM */ - JavaVM *vm; - int env_version; - - /* Reference to the NFCManager instance */ - jobject manager; - - /* Cached objects */ - jobject cached_NfcTag; - jobject cached_P2pDevice; - - /* Target discovery configuration */ - int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - - /* Secure Element selected */ - int seId; - - /* LLCP params */ - int lto; - int miu; - int wks; - int opt; - - /* Tag detected */ - jobject tag; - - /* Lib Status */ - NFCSTATUS status; - - /* p2p modes */ - int p2p_initiator_modes; - int p2p_target_modes; - -}; - -typedef struct nfc_jni_native_monitor -{ - /* Mutex protecting native library against reentrance */ - pthread_mutex_t reentrance_mutex; - - /* Mutex protecting native library against concurrency */ - pthread_mutex_t concurrency_mutex; - - /* List used to track pending semaphores waiting for callback */ - struct listHead sem_list; - - /* List used to track incoming socket requests (and associated sync variables) */ - LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; - pthread_mutex_t incoming_socket_mutex; - pthread_cond_t incoming_socket_cond; - -} nfc_jni_native_monitor_t; - -typedef struct nfc_jni_callback_data -{ - /* Semaphore used to wait for callback */ - sem_t sem; - - /* Used to store the status sent by the callback */ - NFCSTATUS status; - - /* Used to provide a local context to the callback */ - void* pContext; - -} nfc_jni_callback_data_t; - -typedef struct nfc_jni_listen_data -{ - /* LLCP server socket receiving the connection request */ - phLibNfc_Handle pServerSocket; - - /* LLCP socket created from the connection request */ - phLibNfc_Handle pIncomingSocket; - - /* List entries */ - LIST_ENTRY(nfc_jni_listen_data) entries; - -} nfc_jni_listen_data_t; - -/* TODO: treat errors and add traces */ -#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) -#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) -#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) -#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) - -namespace android { - -extern JavaVM *vm; - -JNIEnv *nfc_get_env(); - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); -void nfc_cb_data_releaseAll(); - -const char* nfc_jni_get_status_name(NFCSTATUS status); -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj); -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); - -int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* typeList); - -/* P2P */ -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); - -/* TAG */ -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); - -/* LLCP */ -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e); -int register_com_android_nfc_NativeNfcTag(JNIEnv *e); -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); - -} // namespace android - -#endif diff --git a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp deleted file mode 100644 index 188edb4..0000000 --- a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - pCallbackData->pContext = (void*)ssap; - TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_sendTo_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* -* Methods -*/ -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_SendTo()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SendTo(hRemoteDevice, - hLlcpSocket, - nsap, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) -{ - NFCSTATUS ret; - struct timespec ts; - uint8_t ssap; - jobject llcpPacket = NULL; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer; - jclass clsLlcpPacket; - jfieldID f; - jbyteArray receivedData = NULL; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create new LlcpPacket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) - { - ALOGE("Find LlcpPacket class error"); - goto clean_and_return; - } - - /* Get NativeConnectionless class object */ - clsLlcpPacket = e->GetObjectClass(llcpPacket); - if(e->ExceptionCheck()) - { - ALOGE("Get Object class error"); - goto clean_and_return; - } - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); - - sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); - sReceiveBuffer.length = linkMiu; - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - &cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ssap = (uint32_t)cb_data.pContext; - TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); - - /* Set Llcp Packet remote SAP */ - f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); - e->SetIntField(llcpPacket, f,(jbyte)ssap); - - /* Set Llcp Packet Buffer */ - ALOGD("Set LlcpPacket Data Buffer\n"); - f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); - receivedData = e->NewByteArray(sReceiveBuffer.length); - e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); - e->SetObjectField(llcpPacket, f, receivedData); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return llcpPacket; -} - -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - TRACE("Close Connectionless socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, - - {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, - - {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", - gMethods, NELEM(gMethods)); -} - -} // android namespace diff --git a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp deleted file mode 100644 index 92de3e4..0000000 --- a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode); -/* - * Callbacks - */ -static void nfc_jni_llcp_accept_socket_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -/* - * Utils - */ - -static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, - phLibNfc_Handle hServerSocket) -{ - nfc_jni_listen_data_t * pListenData; - phLibNfc_Handle pIncomingSocket = NULL; - - /* Look for a pending incoming connection on the current server */ - LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) - { - if (pListenData->pServerSocket == hServerSocket) - { - pIncomingSocket = pListenData->pIncomingSocket; - LIST_REMOVE(pListenData, entries); - free(pListenData); - break; - } - } - - return pIncomingSocket; -} - -/* - * Methods - */ -static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret = NFCSTATUS_SUCCESS; - struct timespec ts; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - jfieldID f; - jclass clsNativeLlcpSocket; - jobject clientSocket = NULL; - struct nfc_jni_callback_data cb_data; - phLibNfc_Handle hIncomingSocket, hServerSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Get server socket */ - hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Set socket options with the socket options of the service */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - - while(cb_data.status != NFCSTATUS_SUCCESS) - { - /* Wait for tag Notification */ - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { - pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); - } - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - /* Accept the incomming socket */ - TRACE("phLibNfc_Llcp_Accept()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Accept( hIncomingSocket, - &sOptions, - &sWorkingBuffer, - nfc_jni_llcp_transport_socket_err_callback, - nfc_jni_llcp_accept_socket_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - // NOTE: This may happen if link went down since incoming socket detected, then - // just drop it and start a new accept loop. - ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - continue; - } - TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ - ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); - } - } - - /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGD("LLCP Socket creation error"); - goto clean_and_return; - } - - /* Get NativeConnectionOriented class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGD("LLCP Socket get class object error"); - goto clean_and_return; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hIncomingSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - - TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return clientSocket; -} - -static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - TRACE("Close Service socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - /* TODO: implement accept abort */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("Close Service socket OK"); - return TRUE; - } - else - { - ALOGD("Close Service socket KO"); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_NativeLlcpServiceSocket_doAccept}, - - {"doClose", "()Z", - (void *)com_NativeLlcpServiceSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeLlcpSocket.cpp b/jni/com_android_nfc_NativeLlcpSocket.cpp deleted file mode 100644 index 0c0b830..0000000 --- a/jni/com_android_nfc_NativeLlcpSocket.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_disconnect_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - TRACE("Socket connected\n"); - } - else - { - ALOGD("Socket not connected:"); - switch(nErrCode) - { - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: - { - ALOGD("> SAP NOT ACTIVE\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: - { - ALOGD("> SAP NOT FOUND\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: - { - ALOGD("> CONNECT REJECTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: - { - ALOGD("> CONNECT NOT ACCEPTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: - { - ALOGD("> SOCKET NOT AVAILABLE\n"); - }break; - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - - - -static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Methods - */ -static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_Llcp_Connect(%d)",nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Connect(hRemoteDevice, - hLlcpSocket, - nSap, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("LLCP Connect request failed"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) -{ - NFCSTATUS ret; - struct timespec ts; - phNfc_sData_t serviceName = {0}; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Service socket */ - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - - TRACE("phLibNfc_Llcp_ConnectByUri()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, - hLlcpSocket, - &serviceName, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_Send()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Send(hRemoteDevice, - hLlcpSocket, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jint result = -1; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); - sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); - - TRACE("phLibNfc_Llcp_Recv()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Recv(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_PENDING) - { - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - } - else if (ret == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - else - { - /* Return status should be either SUCCESS or PENDING */ - ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - -clean_and_return: - if (sReceiveBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.miu; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.rw; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnect}, - - {"doConnectBy", "(Ljava/lang/String;)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, - - {"doClose", "()Z", - (void *)com_android_nfc_NativeLlcpSocket_doClose}, - - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeLlcpSocket_doSend}, - - {"doReceive", "([B)I", - (void *)com_android_nfc_NativeLlcpSocket_doReceive}, - - {"doGetRemoteSocketMiu", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, - - {"doGetRemoteSocketRw", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, -}; - - -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp deleted file mode 100644 index e6da0fa..0000000 --- a/jni/com_android_nfc_NativeNfcManager.cpp +++ /dev/null @@ -1,2623 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "com_android_nfc.h" - -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -extern uint32_t libnfc_llc_error_count; - -static phLibNfc_sConfig_t gDrvCfg; -void *gHWRef; -static phNfc_sData_t gInputParam; -static phNfc_sData_t gOutputParam; - -uint8_t device_connected_flag; -static bool driverConfigured = FALSE; - -static phLibNfc_Handle hLlcpHandle; -static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; -static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; - -static jmethodID cached_NfcManager_notifyNdefMessageListeners; -static jmethodID cached_NfcManager_notifyTransactionListeners; -static jmethodID cached_NfcManager_notifyLlcpLinkActivation; -static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; -static jmethodID cached_NfcManager_notifyTargetDeselected; - -static jmethodID cached_NfcManager_notifySeFieldActivated; -static jmethodID cached_NfcManager_notifySeFieldDeactivated; - -static jmethodID cached_NfcManager_notifySeApduReceived; -static jmethodID cached_NfcManager_notifySeMifareAccess; -static jmethodID cached_NfcManager_notifySeEmvCardRemoval; - -namespace android { - -phLibNfc_Handle storedHandle = 0; - -struct nfc_jni_native_data *exported_nat = NULL; - -/* Internal functions declaration */ -static void *nfc_jni_client_thread(void *arg); -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_se_set_mode_callback(void *context, - phLibNfc_Handle handle, NFCSTATUS status); -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status); -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); -static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); - -/* - * Deferred callback called when client thread must be exited - */ -static void client_kill_deferred_call(void* arg) -{ - struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; - - nat->running = FALSE; -} - -static void kill_client(nfc_jni_native_data *nat) -{ - phDal4Nfc_Message_Wrapper_t wrapper; - phLibNfc_DeferredCall_t *pMsg; - - usleep(50000); - - ALOGD("Terminating client thread..."); - - pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); - pMsg->pCallback = client_kill_deferred_call; - pMsg->pParameter = (void*)nat; - - wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; - wrapper.msg.pMsgData = pMsg; - wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); - - phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); -} - -static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_ioctl_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_deinit_download_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) -{ - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - struct timespec ts; - NFCSTATUS status = NFCSTATUS_FAILED; - phLibNfc_StackCapabilities_t caps; - struct nfc_jni_callback_data cb_data; - bool result; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - if(update) - { - //deinit - TRACE("phLibNfc_Mgt_DeInitialize() (download)"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts)) - { - ALOGW("Deinitialization timed out (download)"); - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("Deinitialization FAILED (download)"); - } - TRACE("Deinitialization SUCCESS (download)"); - } - - result = performDownload(nat, false); - - if (!result) { - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - status = cb_data.status; - goto clean_and_return; - } - - /* ====== CAPABILITIES ======= */ - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /*Download is successful*/ - status = NFCSTATUS_SUCCESS; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return status; -} - -static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) -{ - char value[PROPERTY_VALUE_MAX]; - int result = FALSE; - NFCSTATUS status; - - /* ====== CONFIGURE DRIVER ======= */ - /* Configure hardware link */ - gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); - - TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); - REENTRANCE_UNLOCK(); - if(status == NFCSTATUS_ALREADY_INITIALISED) { - ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) - { - ALOGE("pthread_create failed"); - goto clean_and_return; - } - - driverConfigured = TRUE; - -clean_and_return: - return result; -} - -static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) -{ - int result = FALSE; - NFCSTATUS status; - - /* Unconfigure driver */ - TRACE("phLibNfc_Mgt_UnConfigureDriver()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); - } - else - { - ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = TRUE; - } - - driverConfigured = FALSE; - - return result; -} - -/* Initialization function */ -static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { - struct timespec ts; - uint8_t resp[16]; - NFCSTATUS status; - phLibNfc_StackCapabilities_t caps; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; - phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; - struct nfc_jni_callback_data cb_data; - uint8_t firmware_status; - uint8_t update = TRUE; - int result = JNI_FALSE; - const hw_module_t* hw_module; - nfc_pn544_device_t* pn544_dev = NULL; - int ret = 0; - ALOGD("Start Initialization\n"); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Get EEPROM values and device port from product-specific settings */ - ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); - if (ret) { - ALOGE("hw_get_module() failed."); - goto clean_and_return; - } - ret = nfc_pn544_open(hw_module, &pn544_dev); - if (ret) { - ALOGE("Could not open pn544 hw_module."); - goto clean_and_return; - } - if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { - ALOGE("Could not load EEPROM settings"); - goto clean_and_return; - } - - /* Reset device connected handle */ - device_connected_flag = 0; - - /* Reset stored handle */ - storedHandle = 0; - - /* Initialize Driver */ - if(!driverConfigured) - { - nfc_jni_configure_driver(nat); - } - - /* ====== INITIALIZE ======= */ - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - update = FALSE; - goto force_download; - } - TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - update = FALSE; - goto force_download; - } - - /* ====== CAPABILITIES ======= */ - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /* ====== FIRMWARE VERSION ======= */ - if(caps.psDevCapabilities.firmware_update_info) - { -force_download: - for (i=0; i<3; i++) - { - TRACE("Firmware version not UpToDate"); - status = nfc_jni_download_locked(nat, update); - if(status == NFCSTATUS_SUCCESS) - { - ALOGI("Firmware update SUCCESS"); - break; - } - ALOGW("Firmware update FAILED"); - update = FALSE; - } - if(i>=3) - { - ALOGE("Unable to update firmware, giving up"); - goto clean_and_return; - } - } - else - { - TRACE("Firmware version UpToDate"); - } - /* ====== EEPROM SETTINGS ======= */ - - // Update EEPROM settings - TRACE("****** START EEPROM SETTINGS UPDATE ******"); - for (i = 0; i < pn544_dev->num_eeprom_settings; i++) - { - char eeprom_property[PROPERTY_KEY_MAX]; - char eeprom_value[PROPERTY_VALUE_MAX]; - uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); - TRACE("> EEPROM SETTING: %d", i); - - // Check for override of this EEPROM value in properties - snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", - eeprom_base[1], eeprom_base[2]); - TRACE(">> Checking property: %s", eeprom_property); - if (property_get(eeprom_property, eeprom_value, "") == 2) { - int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); - ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", - eeprom_base[1], eeprom_base[2], eeprom_value_num); - eeprom_base[3] = eeprom_value_num; - } - - TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], - eeprom_base[3]); - gInputParam.buffer = eeprom_base; - gInputParam.length = 0x04; - gOutputParam.buffer = resp; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if (cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - } - TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); - - /* ====== SECURE ELEMENTS ======= */ - - REENTRANCE_LOCK(); - ALOGD("phLibNfc_SE_GetSecureElementList()"); - status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - - ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i < No_SE; i++) - { - if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); - } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); - } - - /* Set SE mode - Off */ - REENTRANCE_LOCK(); - status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, - phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - } - - /* ====== LLCP ======= */ - - /* LLCP Params */ - TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); - LlcpConfigInfo.miu = nat->miu; - LlcpConfigInfo.lto = nat->lto; - LlcpConfigInfo.wks = nat->wks; - LlcpConfigInfo.option = nat->opt; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, - nfc_jni_llcpcfg_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* ===== DISCOVERY ==== */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.Duration = 300000; /* in ms */ - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Register for the card emulation mode */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); - - - /* ====== END ======= */ - - ALOGI("NFC Initialized"); - - result = TRUE; - -clean_and_return: - if (result != TRUE) - { - if(nat) - { - kill_client(nat); - } - } - if (pn544_dev != NULL) { - nfc_pn544_close(pn544_dev); - } - nfc_cb_data_deinit(&cb_data); - - return result; -} - -static int is_user_build() { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.type", value, ""); - return !strncmp("user", value, PROPERTY_VALUE_MAX); -} - -/* - * Last-chance fallback when there is no clean way to recover - * Performs a software reset - */ -void emergency_recovery(struct nfc_jni_native_data *nat) { - if (!is_user_build()) { - ALOGE("emergency_recovery: force restart of NFC service"); - } else { - // dont recover immediately, so we can debug - unsigned int t; - for (t=1; t < 1000000; t <<= 1) { - ALOGE("emergency_recovery: NFC stack dead-locked"); - sleep(t); - } - } - phLibNfc_Mgt_Recovery(); - abort(); // force a noisy crash -} - -void nfc_jni_reset_timeout_values() -{ - REENTRANCE_LOCK(); - phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); - phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); - phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); - phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); - REENTRANCE_UNLOCK(); -} - -/* - * Restart the polling loop when unable to perform disconnect - */ -void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) -{ - nfc_jni_start_discovery_locked(nat, true); -} - - /* - * Utility to recover UID from target infos - */ -static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - phNfc_sData_t uid; - - switch(psRemoteDevInfo->RemDevType) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_3A_PICC: - case phNfc_eMifare_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; - break; - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; - uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); - break; - case phNfc_eFelica_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; - uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; - break; - case phNfc_eJewel_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; - break; - case phNfc_eISO15693_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; - break; - case phNfc_eNfcIP1_Target: - case phNfc_eNfcIP1_Initiator: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; - uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; - break; - default: - uid.buffer = NULL; - uid.length = 0; - break; - } - - return uid; -} - -/* - * NFC stack message processing - */ -static void *nfc_jni_client_thread(void *arg) -{ - struct nfc_jni_native_data *nat; - JNIEnv *e; - JavaVMAttachArgs thread_args; - phDal4Nfc_Message_Wrapper_t wrapper; - - nat = (struct nfc_jni_native_data *)arg; - - thread_args.name = "NFC Message Loop"; - thread_args.version = nat->env_version; - thread_args.group = NULL; - - nat->vm->AttachCurrentThread(&e, &thread_args); - pthread_setname_np(pthread_self(), "message"); - - TRACE("NFC client started"); - nat->running = TRUE; - while(nat->running == TRUE) - { - /* Fetch next message from the NFC stack message queue */ - if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, - sizeof(phLibNfc_Message_t), 0, 0) == -1) - { - ALOGE("NFC client received bad message"); - continue; - } - - switch(wrapper.msg.eMsgType) - { - case PH_LIBNFC_DEFERREDCALL_MSG: - { - phLibNfc_DeferredCall_t *msg = - (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); - - REENTRANCE_LOCK(); - msg->pCallback(msg->pParameter); - REENTRANCE_UNLOCK(); - - break; - } - } - } - TRACE("NFC client stopped"); - - nat->vm->DetachCurrentThread(); - - return NULL; -} - -extern uint8_t nfc_jni_is_ndef; -extern uint8_t *nfc_jni_ndef_buf; -extern uint32_t nfc_jni_ndef_buf_len; - -static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = -{ - 3, - { 0x46, 0x66, 0x6D } -}; - -/* - * Callbacks - */ - -/* P2P - LLCP callbacks */ -static void nfc_jni_llcp_linkStatus_callback(void *pContext, - phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) -{ - phFriNfc_Llcp_sLinkParameters_t sLinkParams; - JNIEnv *e; - NFCSTATUS status; - - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; - - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - /* Update link status */ - g_eLinkStatus = eLinkStatus; - - if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) - { - REENTRANCE_LOCK(); - status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGW("GetRemote Info failded - Status = %02x",status); - } - else - { - ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, - sLinkParams.miu, - sLinkParams.option, - sLinkParams.wks); - device_connected_flag = 1; - } - } - else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) - { - ALOGI("LLCP Link deactivated"); - free(pContextData); - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Reset incoming socket list */ - while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) - { - pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); - LIST_REMOVE(pListenData, entries); - free(pListenData); - } - - /* Notify manager that the LLCP is lost or deactivated */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } -} - -static void nfc_jni_checkLlcp_callback(void *context, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; - - LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, - phLibNfc_Handle hIncomingSocket) -{ - phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - - /* Store the connection request */ - pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); - if (pListenData == NULL) - { - ALOGE("Failed to create structure to handle incoming LLCP connection request"); - goto clean_and_return; - } - pListenData->pServerSocket = hServiceSocket; - pListenData->pIncomingSocket = hIncomingSocket; - LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); - - /* Signal pending accept operations that the list is updated */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - -clean_and_return: - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); -} - -void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode) -{ - PHNFC_UNUSED_VARIABLE(pContext); - - TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); - - if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) - { - ALOGW("Frame Rejected - Disconnected"); - } - else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) - { - ALOGD("Socket Disconnected"); - } -} - - -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_discover_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNoOfRemoteDev) -{ - // Always prefer p2p targets over other targets. Otherwise, select the first target - // reported. - uint8_t preferred_index = 0; - for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { - if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { - preferred_index = i; - } - } - return preferred_index; -} - -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status) -{ - JNIEnv *e; - NFCSTATUS ret; - jclass tag_cls = NULL; - jobject target_array; - jobject tag; - jmethodID ctor; - jfieldID f; - const char * typeName; - jbyteArray tagUid; - jbyteArray generalBytes = NULL; - struct nfc_jni_native_data *nat; - struct timespec ts; - phNfc_sData_t data; - int i; - int target_index = 0; // Target that will be reported (if multiple can be >0) - - nat = (struct nfc_jni_native_data *)pContext; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); - - /* Notify manager that a target was deselected */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); - TRACE("Discovered %d tags", uNofRemoteDev); - - target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); - - /* Reset device connected flag */ - device_connected_flag = 1; - phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; - phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - - tag_cls = e->GetObjectClass(nat->cached_P2pDevice); - if(e->ExceptionCheck()) - { - ALOGE("Get Object Class Error"); - kill_client(nat); - return; - } - - /* New target instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - /* Set P2P Target mode */ - f = e->GetFieldID(tag_cls, "mMode", "I"); - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - ALOGD("Discovered P2P Initiator"); - e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); - } - else - { - ALOGD("Discovered P2P Target"); - e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); - } - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - /* Set General Bytes */ - f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes length ="); - for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) - { - ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); - } - - generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - - e->SetByteArrayRegion(generalBytes, 0, - remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, - (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); - - e->SetObjectField(tag, f, generalBytes); - } - - /* Set tag handle */ - f = e->GetFieldID(tag_cls, "mHandle", "I"); - e->SetIntField(tag, f,(jint)remDevHandle); - TRACE("Target handle = 0x%08x",remDevHandle); - } - else - { - tag_cls = e->GetObjectClass(nat->cached_NfcTag); - if(e->ExceptionCheck()) - { - kill_client(nat); - return; - } - - /* New tag instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - bool multi_protocol = false; - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - TRACE("Multiple Protocol TAG detected\n"); - multi_protocol = true; - } - - /* Set tag UID */ - f = e->GetFieldID(tag_cls, "mUid", "[B"); - data = get_target_uid(remDevInfo); - tagUid = e->NewByteArray(data.length); - if(data.length > 0) - { - e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); - } - e->SetObjectField(tag, f, tagUid); - - /* Generate technology list */ - jintArray techList; - jintArray handleList; - jintArray typeList; - nfc_jni_get_technology_tree(e, psRemoteDevList, - multi_protocol ? uNofRemoteDev : 1, - &techList, &handleList, &typeList); - - /* Push the technology list into the java object */ - f = e->GetFieldID(tag_cls, "mTechList", "[I"); - e->SetObjectField(tag, f, techList); - - f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); - e->SetObjectField(tag, f, handleList); - - f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); - e->SetObjectField(tag, f, typeList); - - f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); - e->SetIntField(tag, f,(jint)-1); - - f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); - e->SetIntField(tag, f,(jint)-1); - } - - storedHandle = remDevHandle; - if (nat->tag != NULL) { - e->DeleteGlobalRef(nat->tag); - } - nat->tag = e->NewGlobalRef(tag); - - /* Notify the service */ - TRACE("Notify Nfc Service"); - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - /* Store the hanlde of the P2P device */ - hLlcpHandle = remDevHandle; - - /* Notify manager that new a P2P device was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - /* Notify manager that new a tag was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - e->DeleteLocalRef(tag); - } -} - -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_init_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_deinit_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Card Emulation callback */ -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) -{ - JNIEnv *e; - jobject tmp_array = NULL; - jobject mifare_block = NULL; - struct nfc_jni_native_data *nat; - phNfc_sData_t *aid; - phNfc_sData_t *mifare_command; - struct nfc_jni_callback_data *pCallbackData; - int i=0; - - LOG_CALLBACK("nfc_jni_transaction_callback", status); - - nat = (struct nfc_jni_native_data *)context; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_SUCCESS) - { - switch(evt_type) - { - case phLibNfc_eSE_EvtStartTransaction: - { - TRACE("> SE EVT_START_TRANSACTION"); - if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) - { - aid = &(evt_info->UiccEvtInfo.aid); - - ALOGD("> AID DETECTED"); - - if(aid != NULL) - { - if (TRACE_ENABLED == 1) { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); - } - ALOGD("> AID: %s", aid_str); - } - tmp_array = e->NewByteArray(aid->length); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - goto error; - } - - TRACE("Notify Nfc Service"); - /* Notify manager that a new event occurred on a SE */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - ALOGD("> NO AID DETECTED"); - } - }break; - - case phLibNfc_eSE_EvtApduReceived: - { - phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); - TRACE("> SE EVT_APDU_RECEIVED"); - - if (apdu != NULL) { - TRACE(" APDU length=%d", apdu->length); - tmp_array = e->NewByteArray(apdu->length); - if (tmp_array == NULL) { - goto error; - } - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); - if (e->ExceptionCheck()) { - goto error; - } - } else { - TRACE(" APDU EMPTY"); - } - - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); - }break; - - case phLibNfc_eSE_EvtCardRemoval: - { - TRACE("> SE EVT_EMV_CARD_REMOVAL"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); - }break; - - case phLibNfc_eSE_EvtMifareAccess: - { - TRACE("> SE EVT_MIFARE_ACCESS"); - mifare_command = &(evt_info->UiccEvtInfo.aid); - TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); - tmp_array = e->NewByteArray(2); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); - }break; - - case phLibNfc_eSE_EvtFieldOn: - { - TRACE("> SE EVT_FIELD_ON"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); - }break; - - case phLibNfc_eSE_EvtFieldOff: - { - TRACE("> SE EVT_FIELD_OFF"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); - }break; - - default: - { - TRACE("Unknown SE event"); - }break; - } - } - else - { - ALOGE("SE transaction notification error"); - goto error; - } - - /* Function finished, now clean and return */ - goto clean_and_return; - - error: - /* In case of error, just discard the notification */ - ALOGE("Failed to send SE transaction notification"); - e->ExceptionClear(); - - clean_and_return: - if(tmp_array != NULL) - { - e->DeleteLocalRef(tmp_array); - } -} - -static void nfc_jni_se_set_mode_callback(void *pContext, - phLibNfc_Handle handle, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* - * NFCManager methods - */ - -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) -{ - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ - nfc_jni_reset_timeout_values(); - - /* Reload the p2p modes */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Start Polling loop */ - TRACE("****** Start NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, - nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - -static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) -{ - phLibNfc_sADD_Cfg_t discovery_cfg; - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - discovery_cfg.PollDevInfo.PollEnabled = 0; - discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; - discovery_cfg.NfcIP_Target_Mode = 0; - discovery_cfg.NfcIP_Tgt_Disable = TRUE; - - /* Start Polling loop */ - TRACE("****** Stop NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - - -static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nfc_jni_stop_discovery_locked(nat); - - CONCURRENCY_UNLOCK(); - -} - -static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - nat = nfc_jni_get_nat(e, o); - - /* Register callback for remote device notifications. - * Must re-register every time we turn on discovery, since other operations - * (such as opening the Secure Element) can change the remote device - * notification callback*/ - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", - nat->registry_info.Jewel==TRUE?"J":"", - nat->registry_info.MifareUL==TRUE?"UL":"", - nat->registry_info.MifareStd==TRUE?"Mi":"", - nat->registry_info.Felica==TRUE?"F":"", - nat->registry_info.ISO14443_4A==TRUE?"4A":"", - nat->registry_info.ISO14443_4B==TRUE?"4B":"", - nat->registry_info.NFC==TRUE?"P2P":"", - nat->registry_info.ISO15693==TRUE?"R":"", ret); - - nfc_jni_start_discovery_locked(nat, false); -clean_and_return: - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { - CONCURRENCY_LOCK(); - nfc_jni_reset_timeout_values(); - CONCURRENCY_UNLOCK(); -} - -static void setFelicaTimeout(jint timeout) { - // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. - // It can be set to 0 to disable the timeout altogether, in which case we - // use the sw watchdog as a fallback. - if (timeout <= 255) { - phLibNfc_SetFelicaTimeout(timeout); - } else { - // Disable hw timeout, use sw watchdog for timeout - phLibNfc_SetFelicaTimeout(0); - phLibNfc_SetHciTimeout(timeout); - } - -} -// Calculates ceiling log2 of value -static unsigned int log2(int value) { - unsigned int ret = 0; - bool isPowerOf2 = ((value & (value - 1)) == 0); - while ( (value >> ret) > 1 ) ret++; - if (!isPowerOf2) ret++; - return ret; -} - -// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X -// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X -// -// We keep the constant part of the formula in a static; note the factor -// 1000 off, which is due to the fact that the formula calculates seconds, -// but this method gets milliseconds as an argument. -static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; - -static int calcTimeout(int timeout_in_ms) { - // timeout = (256 * 16 / 13560000) * 2 ^ X - // First find the first X for which timeout > requested timeout - return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); -} - -static void setIsoDepTimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - // Then re-compute the actual timeout based on X - double actual_timeout = nxp_nfc_timeout_factor * (1 << value); - // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, - // but it will take some time to get back through the sw layers. - // 500 ms should be enough). - phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); - value |= 0x10; // bit 4 to enable timeout - phLibNfc_SetIsoXchgTimeout(value); - } - else { - // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout - // must be disabled completely, to prevent the PN544 from aborting - // the transaction. We reuse the HCI sw watchdog to catch the timeout - // in that case. - phLibNfc_SetIsoXchgTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static void setNfcATimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - phLibNfc_SetMifareRawTimeout(value); - } - else { - // Disable mifare raw timeout, use HCI sw watchdog instead - phLibNfc_SetMifareRawTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, - jint tech, jint timeout) { - bool success = false; - CONCURRENCY_LOCK(); - if (timeout <= 0) { - ALOGE("Timeout must be positive."); - return false; - } else { - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - setNfcATimeout(timeout); - success = true; - break; - case TARGET_TYPE_ISO14443_4: - setIsoDepTimeout(timeout); - success = true; - break; - case TARGET_TYPE_FELICA: - setFelicaTimeout(timeout); - success = true; - break; - default: - ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); - success = false; - } - } - CONCURRENCY_UNLOCK(); - return success; -} - -static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, - jint tech) { - int timeout = -1; - CONCURRENCY_LOCK(); - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - timeout = phLibNfc_GetMifareRawTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_ISO14443_4: - timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_FELICA: - timeout = phLibNfc_GetFelicaTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Felica timeout already in ms - } - break; - default: - ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); - break; - } - CONCURRENCY_UNLOCK(); - return timeout; -} - - -static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct nfc_jni_native_data *nat = NULL; - jclass cls; - jobject obj; - jfieldID f; - - TRACE("****** Init Native Structure ******"); - - /* Initialize native structure */ - nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); - if(nat == NULL) - { - ALOGD("malloc of nfc_jni_native_data failed"); - return FALSE; - } - memset(nat, 0, sizeof(*nat)); - e->GetJavaVM(&(nat->vm)); - nat->env_version = e->GetVersion(); - nat->manager = e->NewGlobalRef(o); - - cls = e->GetObjectClass(o); - f = e->GetFieldID(cls, "mNative", "I"); - e->SetIntField(o, f, (jint)nat); - - /* Initialize native cached references */ - cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); - - cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, - "notifyTransactionListeners", "([B)V"); - - cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, - "notifyTargetDeselected","()V"); - - cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, - "notifySeFieldActivated", "()V"); - - cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, - "notifySeFieldDeactivated", "()V"); - - cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, - "notifySeApduReceived", "([B)V"); - - cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, - "notifySeMifareAccess", "([B)V"); - - cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, - "notifySeEmvCardRemoval", "()V"); - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - TRACE("****** Init Native Structure OK ******"); - return TRUE; - -} - -/* Init/Deinit method */ -static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - int init_result = JNI_FALSE; -#ifdef TNFC_EMULATOR_ONLY - char value[PROPERTY_VALUE_MAX]; -#endif - jboolean result; - - CONCURRENCY_LOCK(); - -#ifdef TNFC_EMULATOR_ONLY - if (!property_get("ro.kernel.qemu", value, 0)) - { - ALOGE("NFC Initialization failed: not running in an emulator\n"); - goto clean_and_return; - } -#endif - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nat->seId = SMX_SECURE_ELEMENT_ID; - - nat->lto = 150; // LLCP_LTO - nat->miu = 128; // LLCP_MIU - // WKS indicates well-known services; 1 << sap for each supported SAP. - // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) - nat->wks = 0x13; // LLCP_WKS - nat->opt = 0; // LLCP_OPT - nat->p2p_initiator_modes = phNfc_eP2P_ALL; - nat->p2p_target_modes = 0x0E; // All passive except 106, active - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; - - nat->registry_info.MifareUL = TRUE; - nat->registry_info.MifareStd = TRUE; - nat->registry_info.ISO14443_4A = TRUE; - nat->registry_info.ISO14443_4B = TRUE; - nat->registry_info.Jewel = TRUE; - nat->registry_info.Felica = TRUE; - nat->registry_info.NFC = TRUE; - nat->registry_info.ISO15693 = TRUE; - - exported_nat = nat; - - /* Perform the initialization */ - init_result = nfc_jni_initialize(nat); - -clean_and_return: - CONCURRENCY_UNLOCK(); - - /* Convert the result and return */ - return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; -} - -static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) -{ - struct timespec ts; - NFCSTATUS status; - int result = JNI_FALSE; - struct nfc_jni_native_data *nat; - int bStackReset = FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Clear previous configuration */ - memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); - memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); - - /* Create the local semaphore */ - if (nfc_cb_data_init(&cb_data, NULL)) - { - TRACE("phLibNfc_Mgt_DeInitialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status == NFCSTATUS_PENDING) - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts) == -1) - { - ALOGW("Operation timed out"); - bStackReset = TRUE; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Failed to deinit the stack"); - bStackReset = TRUE; - } - } - else - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - bStackReset = TRUE; - } - nfc_cb_data_deinit(&cb_data); - } - else - { - ALOGE("Failed to create semaphore (errno=0x%08x)", errno); - bStackReset = TRUE; - } - - kill_client(nat); - - if(bStackReset == TRUE) - { - /* Complete deinit. failed, try hard restart of NFC */ - ALOGW("Reseting stack..."); - emergency_recovery(nat); - } - - result = nfc_jni_unconfigure_driver(nat); - - TRACE("NFC Deinitialized"); - - CONCURRENCY_UNLOCK(); - - return TRUE; -} - -/* Secure Element methods */ -static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { - NFCSTATUS ret; - jintArray list= NULL; - phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; - - TRACE("****** Get Secure Element List ******"); - - TRACE("phLibNfc_SE_GetSecureElementList()"); - REENTRANCE_LOCK(); - ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_SUCCESS) { - ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - return list; - } - TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - - TRACE("Nb SE: %d", se_count); - list =e->NewIntArray(se_count); - for (i = 0; i < se_count; i++) { - if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } - e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); - } - - e->DeleteLocalRef(list); - - return list; -} - -static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Select Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Virtual */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING) { - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Deselect Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Default */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, - nfc_jni_se_set_mode_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); - if (ret != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -/* Llcp methods */ - -static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - bool freeData = false; - jboolean result = JNI_FALSE; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data *cb_data; - - - CONCURRENCY_LOCK(); - - /* Memory allocation for cb_data - * This is on the heap because it is used by libnfc - * even after this call has succesfully finished. It is only freed - * upon link closure in nfc_jni_llcp_linkStatus_callback. - */ - cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(cb_data, (void*)nat)) - { - goto clean_and_return; - } - - /* Check LLCP compliancy */ - TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, - nfc_jni_checkLlcp_callback, - nfc_jni_llcp_linkStatus_callback, - (void*)cb_data); - REENTRANCE_UNLOCK(); - /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol - * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - freeData = true; - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data->sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data->status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(cb_data); - if (freeData) { - free(cb_data); - } - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Activate(hLlcpHandle); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_FALSE; - } -} - - - -static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, - jint nSap, jstring sn) -{ - NFCSTATUS ret; - jobject connectionlessSocket = NULL; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_native_data *nat; - phNfc_sData_t sWorkingBuffer = {NULL, 0}; - phNfc_sData_t serviceName = {NULL, 0}; - phLibNfc_Llcp_sLinkParameters_t sParams; - jclass clsNativeConnectionlessSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Allocate Working buffer length */ - phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); - sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, - NULL, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - - /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) - { - goto error; - } - - /* Get NativeConnectionless class object */ - clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); - if(e->ExceptionCheck()) - { - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); - e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); - TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); - - /* Set the miu link of the connectionless socket */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); - e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); - TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); - e->SetIntField(connectionlessSocket, f,(jint)nSap); - TRACE("Connectionless socket SAP = %d\n",nSap); - - return connectionlessSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - - if (sWorkingBuffer.buffer != NULL) { - free(sWorkingBuffer.buffer); - } - - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - phNfc_sData_t serviceName; - struct nfc_jni_native_data *nat; - jobject serviceSocket = NULL; - jclass clsNativeLlcpServiceSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - ret = phLibNfc_Llcp_Close(hLlcpSocket); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Listen( hLlcpSocket, - nfc_jni_llcp_transport_listen_socket_callback, - (void*)hLlcpSocket); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - /* Close created socket */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) - { - ALOGE("Llcp Socket object creation error"); - goto error; - } - - /* Get NativeLlcpServiceSocket class object */ - clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); - if(e->ExceptionCheck()) - { - ALOGE("Llcp Socket get object class error"); - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); - e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); - TRACE("Service socket Handle = %02x\n",hLlcpSocket); - - /* Set socket linear buffer length */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); - e->SetIntField(serviceSocket, f,(jint)linearBufferLength); - TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); - e->SetIntField(serviceSocket, f,(jint)miu); - TRACE("Service socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); - e->SetIntField(serviceSocket, f,(jint)rw); - TRACE("Service socket RW = %d\n",rw); - - return serviceSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) -{ - jobject clientSocket = NULL; - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - struct nfc_jni_native_data *nat; - jclass clsNativeLlcpSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - return NULL; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGE("Llcp socket object creation error"); - return NULL; - } - - /* Get NativeConnectionless class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGE("Get class object error"); - return NULL; - } - - /* Test if an SAP number is present */ - if(nSap != 0) - { - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - return NULL; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); - e->SetIntField(clientSocket, f,(jint)nSap); - TRACE("socket SAP = %d\n",nSap); - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hLlcpSocket); - TRACE("socket Handle = %02x\n",hLlcpSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - TRACE("socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - TRACE("socket RW = %d\n",rw); - - - return clientSocket; -} - -static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) -{ - TRACE("Last Error Status = 0x%02x",lastErrorStatus); - - if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) - { - return ERROR_BUFFER_TOO_SMALL; - } - else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) - { - return ERROR_INSUFFICIENT_RESOURCES; - } - else - { - return lastErrorStatus; - } -} - -static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) -{ - emergency_recovery(NULL); -} - -static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting init modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_initiator_modes = modes; -} - -static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting target modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_target_modes = modes; -} - -static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { - bool result = FALSE; - int load_result; - bool wasDisabled = FALSE; - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - NFCSTATUS status = NFCSTATUS_FAILED; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - result = FALSE; - goto clean_and_return; - } - - if (takeLock) - { - CONCURRENCY_LOCK(); - } - - /* Initialize Driver */ - if(!driverConfigured) - { - result = nfc_jni_configure_driver(nat); - wasDisabled = TRUE; - } - TRACE("com_android_nfc_NfcManager_doDownload()"); - - TRACE("Go in Download Mode"); - phLibNfc_Download_Mode(); - - TRACE("Load new Firmware Image"); - load_result = phLibNfc_Load_Firmware_Image(); - if(load_result != 0) - { - TRACE("Load new Firmware Image - status = %d",load_result); - result = FALSE; - goto clean_and_return; - } - - // Download - gInputParam.buffer = InputBuffer; - gInputParam.length = 0x01; - gOutputParam.buffer = OutputBuffer; - gOutputParam.length = 0x01; - - ALOGD("Download new Firmware"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - result = FALSE; - goto clean_and_return; - } - - /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we - try to download an old-style firmware on top of a new-style - firmware. Hence, this is expected behavior, and not an - error condition. */ - if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); - } - - /*Download is successful*/ - result = TRUE; -clean_and_return: - TRACE("phLibNfc_HW_Reset()"); - phLibNfc_HW_Reset(); - /* Deinitialize Driver */ - if(wasDisabled) - { - result = nfc_jni_unconfigure_driver(nat); - } - if (takeLock) - { - CONCURRENCY_UNLOCK(); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - return performDownload(nat, true); -} - -static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); - return e->NewStringUTF(buffer); -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doDownload", "()Z", - (void *)com_android_nfc_NfcManager_doDownload}, - - {"initializeNativeStructure", "()Z", - (void *)com_android_nfc_NfcManager_init_native_struc}, - - {"doInitialize", "()Z", - (void *)com_android_nfc_NfcManager_initialize}, - - {"doDeinitialize", "()Z", - (void *)com_android_nfc_NfcManager_deinitialize}, - - {"enableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_enableDiscovery}, - - {"doGetSecureElementList", "()[I", - (void *)com_android_nfc_NfcManager_doGetSecureElementList}, - - {"doSelectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doSelectSecureElement}, - - {"doDeselectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, - - {"doCheckLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doCheckLlcp}, - - {"doActivateLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doActivateLlcp}, - - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, - - {"doGetLastError", "()I", - (void *)com_android_nfc_NfcManager_doGetLastError}, - - {"disableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_disableDiscovery}, - - {"doSetTimeout", "(II)Z", - (void *)com_android_nfc_NfcManager_doSetTimeout}, - - {"doGetTimeout", "(I)I", - (void *)com_android_nfc_NfcManager_doGetTimeout}, - - {"doResetTimeouts", "()V", - (void *)com_android_nfc_NfcManager_doResetTimeouts}, - - {"doAbort", "()V", - (void *)com_android_nfc_NfcManager_doAbort}, - - {"doSetP2pInitiatorModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, - - {"doSetP2pTargetModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, - - {"doDump", "()Ljava/lang/String;", - (void *)com_android_nfc_NfcManager_doDump}, -}; - - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e) -{ - nfc_jni_native_monitor_t *nfc_jni_native_monitor; - - nfc_jni_native_monitor = nfc_jni_init_monitor(); - if(nfc_jni_native_monitor == NULL) - { - ALOGE("NFC Manager cannot recover native monitor %x\n", errno); - return -1; - } - - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", - gMethods, NELEM(gMethods)); -} - -} /* namespace android */ diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp deleted file mode 100755 index bf0bffc..0000000 --- a/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "com_android_nfc.h" - -static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; -static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; -static phNfc_sRemoteDevInformation_t* SecureElementInfo; -static int secureElementHandle; -extern void *gHWRef; -static int SecureElementTech; -extern uint8_t device_connected_flag; - -namespace android { - -static void com_android_nfc_jni_ioctl_callback ( void* pContext, - phNfc_sData_t* Outparam_Cb, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if (status == NFCSTATUS_SUCCESS ) - { - LOG_CALLBACK("> IOCTL successful",status); - } - else - { - LOG_CALLBACK("> IOCTL error",status); - } - - com_android_nfc_jni_ioctl_buffer = Outparam_Cb; - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); - - com_android_nfc_jni_transceive_buffer = pResBuffer; - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static void com_android_nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if(status==NFCSTATUS_SUCCESS) - { - LOG_CALLBACK("SE Set Mode is Successful",status); - TRACE("SE Handle: %lu", hSecureElement); - } - else - { - LOG_CALLBACK("SE Set Mode is failed\n ",status); - } - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - NFCSTATUS ret; - int i; - JNIEnv *e = nfc_get_env(); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); - } - else - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); - TRACE("Discovered %d secure elements", uNofRemoteDev); - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - bool foundHandle = false; - TRACE("Multiple Protocol supported\n"); - for (i=0; iRemDevType); - if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { - secureElementHandle = psRemoteDevList[i].hTargetDev; - foundHandle = true; - } - } - if (!foundHandle) { - ALOGE("Could not find ISO-DEP secure element"); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - } - else - { - secureElementHandle = psRemoteDevList->hTargetDev; - } - - TRACE("Secure Element Handle: 0x%08x", secureElementHandle); - - /* Set type name */ - jintArray techList; - nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); - - // TODO: Should use the "connected" technology, for now use the first - if ((techList != NULL) && e->GetArrayLength(techList) > 0) { - e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); - TRACE("Store Secure Element Info\n"); - SecureElementInfo = psRemoteDevList->psRemoteDevInfo; - - TRACE("Discovered secure element: tech=%d", SecureElementTech); - } - else { - ALOGE("Discovered secure element, but could not resolve tech"); - status = NFCSTATUS_FAILED; - } - - // This thread may not return to the virtual machine for a long time - // so make sure to delete the local refernce to the tech list. - e->DeleteLocalRef(techList); - } - -clean_and_return: - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - int semResult; - - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - uint8_t Output_Buff[10]; - uint8_t reg_value; - uint8_t mask_value; - struct nfc_jni_callback_data cb_data; - struct nfc_jni_callback_data cb_data_SE_Notification; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) - { - goto clean_and_return; - } - - /* Registery */ - registry_info.MifareUL = TRUE; - registry_info.MifareStd = TRUE; - registry_info.ISO14443_4A = TRUE; - registry_info.ISO14443_4B = TRUE; - registry_info.Jewel = TRUE; - registry_info.Felica = TRUE; - registry_info.NFC = FALSE; - - CONCURRENCY_LOCK(); - - TRACE("Open Secure Element"); - - /* Check if NFC device is already connected to a tag or P2P peer */ - if (device_connected_flag == 1) - { - ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); - goto clean_and_return; - } - - /* Test if External RF field is detected */ - InParam.buffer = ExternalRFDetected; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - /* Check the value */ - reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; - mask_value = reg_value & 0x40; - - if(mask_value == 0x40) - { - // There is an external RF field present, fail the open request - ALOGD("Unable to open SE connection, external RF Field detected"); - goto clean_and_return; - } - - /* Get Secure Element List */ - TRACE("phLibNfc_SE_GetSecureElementList()"); - ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); - if (ret == NFCSTATUS_SUCCESS) - { - TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i SMX detected"); - TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); - /* save SMARTMX index */ - SmartMX_detected = 1; - SmartMX_index = i; - } - } - - if(SmartMX_detected) - { - REENTRANCE_LOCK(); - TRACE("phLibNfc_RemoteDev_NtfRegister()"); - ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, - com_android_nfc_jni_open_secure_element_notification_callback, - (void *)&cb_data_SE_Notification); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("Register Notification error"); - goto clean_and_return; - } - - /* Set wired mode */ - REENTRANCE_LOCK(); - TRACE("phLibNfc_SE_SetMode: Wired mode"); - ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, - phLibNfc_SE_ActModeWired, - com_android_nfc_jni_smartMX_setModeCb, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING ) - { - ALOGE("\n> SE Set SmartMX mode ERROR \n" ); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("SE set mode failed"); - goto clean_and_return; - } - - TRACE("Waiting for notification"); - /* Wait for callback response */ - if(sem_wait(&cb_data_SE_Notification.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && - cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) - { - ALOGE("SE detection failed"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Connect Tag */ - CONCURRENCY_LOCK(); - TRACE("phLibNfc_RemoteDev_Connect(SMX)"); - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("CONNECT semaphore error"); - goto clean_and_return; - } - - /* Connect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Secure Element connect error"); - goto clean_and_return; - } - - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue | 0x40); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - /* Return the Handle of the SecureElement */ - return secureElementHandle; - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); - goto clean_and_return; - } - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - CONCURRENCY_UNLOCK(); - return 0; -} - - -static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) -{ - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - uint32_t SmartMX_Handle; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t Output_Buff[10]; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Close Secure element function "); - - CONCURRENCY_LOCK(); - /* Disconnect */ - TRACE("Disconnecting from SMX (handle = 0x%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, - NFC_SMARTMX_RELEASE, - com_android_nfc_jni_disconnect_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("\n> Disconnect SE ERROR \n" ); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue & 0xBF); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, - jobject o,jint handle, jbyteArray data) -{ - uint8_t offset = 0; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - - int tech = SecureElementTech; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Exchange APDU function "); - - CONCURRENCY_LOCK(); - - TRACE("Secure Element tech: %d\n", tech); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - /* Prepare transceive info structure */ - if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) - { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - else if(tech == TARGET_TYPE_ISO14443_4) - { - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - } - - transceive_info.sSendData.buffer = buf + offset; - transceive_info.sSendData.length = buflen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - com_android_nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("TRANSCEIVE semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("TRANSCEIVE error"); - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); - if(result != NULL) - { - e->SetByteArrayRegion(result, 0, - com_android_nfc_jni_transceive_buffer->length, - (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) -{ - TRACE("Get Secure element UID function "); - jbyteArray SecureElementUid; - - if(handle == secureElementHandle) - { - SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); - e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); - return SecureElementUid; - } - else - { - return NULL; - } -} - -static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) -{ - jintArray techList; - TRACE("Get Secure element Type function "); - - if(handle == secureElementHandle) - { - techList = e->NewIntArray(1); - e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); - return techList; - } - else - { - return NULL; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doNativeOpenSecureElementConnection", "()I", - (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, - {"doNativeDisconnectSecureElementConnection", "(I)Z", - (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, - {"doTransceive", "(I[B)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, - {"doGetUid", "(I)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, - {"doGetTechList", "(I)[I", - (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, -}; - -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp deleted file mode 100644 index dbf8dc9..0000000 --- a/jni/com_android_nfc_NativeNfcTag.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" -#include "phNfcHalTypes.h" - -static phLibNfc_Data_t nfc_jni_ndef_rw; -static phLibNfc_Handle handle; -uint8_t *nfc_jni_ndef_buf = NULL; -uint32_t nfc_jni_ndef_buf_len = 0; - -extern uint8_t device_connected_flag; - -namespace android { - -extern phLibNfc_Handle storedHandle; - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); -extern void nfc_jni_reset_timeout_values(); - -/* - * Callbacks - */ - static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_tag_rw_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - if (pCallbackData->pContext != NULL) { - // Store the remote dev info ptr in the callback context - // Note that this ptr will remain valid, it is tied to a statically - // allocated buffer in libnfc. - phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = - (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; - *ppRemoteDevInfo = psRemoteDevInfo; - } - - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_checkndef_callback(void *pContext, - phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_checkndef_callback", status); - phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); - if(status == NFCSTATUS_OK) - { - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; - nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); - if (pNdefInfo != NULL) *pNdefInfo = info; - } - else { - if (pNdefInfo != NULL) { - memset(pNdefInfo, 0, sizeof(*pNdefInfo)); - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_async_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; -} - -static phNfc_sData_t *nfc_jni_transceive_buffer; - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - nfc_jni_transceive_buffer = pResBuffer; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presencecheck_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_formatndef_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_readonly_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* Functions */ -static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, - jobject o) -{ - NFCSTATUS status; - phLibNfc_Handle handle = 0; - jbyteArray buf = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; - nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; - - TRACE("phLibNfc_Ndef_Read()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, - phLibNfc_Ndef_EBegin, - nfc_jni_tag_rw_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - buf = e->NewByteArray(nfc_jni_ndef_rw.length); - e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, - (jbyte *)nfc_jni_ndef_rw.buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - - return buf; -} - - -static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, - jobject o, jbyteArray buf) -{ - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); - nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_Ndef_Write()"); - TRACE("Ndef Handle :0x%x\n",handle); - TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * Utility to recover poll bytes from target infos - */ -static void set_target_pollBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); - - jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingPollBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - jint *techId = e->GetIntArrayElements(techList, 0); - int techListLength = e->GetArrayLength(techList); - - jbyteArray pollBytes = e->NewByteArray(0); - jobjectArray techPollBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(pollBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) - { - /* ISO14443-3A: ATQA/SENS_RES */ - case TARGET_TYPE_ISO14443_3A: - if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { - // Jewel ATQA is not read and stored by the PN544, but it is fixed - // at {0x00, 0x0C} in the spec. So eJewel can safely be - // translated to {0x00, 0x0C}. - const static jbyte JewelAtqA[2] = {0x00, 0x0C}; - pollBytes = e->NewByteArray(2); - e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); - } - else { - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); - } - break; - /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ - case TARGET_TYPE_ISO14443_3B: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); - break; - /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ - case TARGET_TYPE_FELICA: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - pollBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techPollBytes, tech, pollBytes); - } - - e->SetObjectField(tag, f, techPollBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); - -} - -/* - * Utility to recover activation bytes from target infos - */ -static void set_target_activationBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - - jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); - jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingActBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - int techListLength = e->GetArrayLength(techList); - jint *techId = e->GetIntArrayElements(techList, 0); - - jbyteArray actBytes = e->NewByteArray(0); - jobjectArray techActBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(actBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) { - - /* ISO14443-3A: SAK/SEL_RES */ - case TARGET_TYPE_ISO14443_3A: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); - break; - /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ - /* ISO14443-3B & ISO14443-4: HiLayerResp */ - case TARGET_TYPE_ISO14443_4: - // Determine whether -A or -B - if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); - e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); - } - else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); - e->SetByteArrayRegion(actBytes, 0, - psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); - } - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - actBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techActBytes, tech, actBytes); - } - e->SetObjectField(tag, f, techActBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); -} - -static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - // Success, set poll & act bytes - set_target_pollBytes(e, o, pRemDevInfo); - set_target_activationBytes(e, o, pRemDevInfo); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, - jobject o) -{ - // Reconnect is provided by libnfc by just calling connect again - // on the same handle. - int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - if (libNfcType != -1) { - // Note that some tag types are stateless, hence we do not reconnect - // those. Currently those are the Jewel and Iso15693 technologies. - if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); - return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); - } - else { - return NFCSTATUS_SUCCESS; - } - } - else { - return NFCSTATUS_REJECTED; - } -} - - -static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_connected_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Reset the stored handle */ - storedHandle = 0; - - nfc_jni_reset_timeout_values(); - - /* Disconnect */ - TRACE("Disconnecting from tag (%x)", handle); - - if (handle == -1) { - // Was never connected to any tag, exit - result = JNI_TRUE; - ALOGE("doDisconnect() - Target already disconnected"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, - nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - result = JNI_TRUE; - TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); - goto clean_and_return; - } - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static uint16_t -crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) -{ - uint16_t b, crc = init; - - do { - b = *msg++ ^ (crc & 0xFF); - b ^= (b << 4) & 0xFF; - crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); - } while( --len ); - - return crc; -} - -static void -nfc_insert_crc_a( uint8_t* msg, size_t len ) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - msg[len] = crc & 0xFF; - msg[len + 1] = (crc >> 8) & 0xFF; -} - -static void -nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - *byte1 = crc & 0xFF; - *byte2 = (crc >> 8) & 0xFF; -} - -static bool -crc_valid( uint8_t* msg, size_t len) -{ - uint8_t crcByte1, crcByte2; - - nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, - len - 2, &crcByte1, &crcByte2); - - if (msg[len - 2] == crcByte1 && - msg[len - 1] == crcByte2) { - return true; - } - else { - return false; - } - -} - -static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, - jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) -{ - uint8_t offset = 0; - // buf is the pointer to the JNI array and never overwritten, - // outbuf is passed into the transceive - it may be pointed to new memory - // to be extended with CRC. - uint8_t *buf = NULL; - uint32_t buflen; - - uint8_t *outbuf = NULL; - uint32_t outlen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - int selectedTech = 0; - int selectedLibNfcType = 0; - jint* technologies = NULL; - bool checkResponseCrc = false; - - jint *targetLost; - if (statusTargetLost != NULL) { - targetLost = e->GetIntArrayElements(statusTargetLost, 0); - if (targetLost != NULL) { - *targetLost = 0; - } - } else { - targetLost = NULL; - } - - memset(&transceive_info, 0, sizeof(transceive_info)); - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - selectedTech = nfc_jni_get_connected_technology(e, o); - selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - - buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = outlen = (uint32_t)e->GetArrayLength(data); - - switch (selectedTech) { - case TARGET_TYPE_FELICA: - transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - if (raw) { - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - break; - case TARGET_TYPE_ISO14443_3A: - // Check which libnfc type - if (selectedLibNfcType == phNfc_eJewel_PICC) { - // For the Jewel pipe, CRC is automatically computed - transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; - transceive_info.addr = 0; - } else { - if (raw) { - // Use Mifare Raw to implement a standard - // ISO14443-3A transceive, with CRC added - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - // Use the mifare pipe - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - - } - break; - case TARGET_TYPE_ISO14443_4: - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_ISO15693: - transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; - transceive_info.addr = 0; - break; - case TARGET_TYPE_UNKNOWN: - case TARGET_TYPE_ISO14443_3B: - // Not supported - goto clean_and_return; - default: - break; - } - - transceive_info.sSendData.buffer = outbuf + offset; - transceive_info.sSendData.length = outlen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - - /* Copy results back to Java * - * In case of NfcA and raw, also check the CRC in the response - * and cut it off in the returned data. - */ - if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { - if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { - result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length - 2, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } - } else { - result = e->NewByteArray(nfc_jni_transceive_buffer->length); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - if ((outbuf != buf) && (outbuf != NULL)) { - // Buf was extended and re-alloced with crc bytes, free separately - free(outbuf); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)buf, JNI_ABORT); - - if (targetLost != NULL) { - e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); - } - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, - jint libnfcType, jint javaType) -{ - jint ndefType = NDEF_UNKNOWN_TYPE; - - switch (libnfcType) { - case phNfc_eJewel_PICC: - ndefType = NDEF_TYPE1_TAG; - break; - case phNfc_eISO14443_3A_PICC: - ndefType = NDEF_TYPE2_TAG;; - break; - case phNfc_eFelica_PICC: - ndefType = NDEF_TYPE3_TAG; - break; - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - ndefType = NDEF_TYPE4_TAG; - break; - case phNfc_eMifare_PICC: - if (javaType == TARGET_TYPE_MIFARE_UL) { - ndefType = NDEF_TYPE2_TAG; - } else { - ndefType = NDEF_MIFARE_CLASSIC_TAG; - } - break; - case phNfc_eISO15693_PICC: - ndefType = NDEF_ICODE_SLI_TAG; - break; - default: - ndefType = NDEF_UNKNOWN_TYPE; - break; - } - return ndefType; -} - -static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) -{ - phLibNfc_Handle handle = 0; - jint status; - phLibNfc_ChkNdef_Info_t sNdefInfo; - struct nfc_jni_callback_data cb_data; - jint *ndef = e->GetIntArrayElements(ndefinfo, 0); - int apiCardState = NDEF_MODE_UNKNOWN; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - cb_data.pContext = &sNdefInfo; - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_Ndef_CheckNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); - - if (status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ndef[0] = sNdefInfo.MaxNdefMsgLength; - // Translate the card state to know values for the NFC API - switch (sNdefInfo.NdefCardState) { - case PHLIBNFC_NDEF_CARD_INITIALISED: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_READ_ONLY: - apiCardState = NDEF_MODE_READ_ONLY; - break; - case PHLIBNFC_NDEF_CARD_READ_WRITE: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_INVALID: - apiCardState = NDEF_MODE_UNKNOWN; - break; - } - ndef[1] = apiCardState; - -clean_and_return: - e->ReleaseIntArrayElements(ndefinfo, ndef, 0); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_RemoteDev_CheckPresence()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, - jobject o, jbyteArray pollBytes, jbyteArray actBytes) -{ - // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire - // is supported. - jboolean result = JNI_FALSE; - - // DESfire has one sak byte and 2 ATQA bytes - if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && - actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { - jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); - jbyte* act = e->GetByteArrayElements(actBytes, NULL); - if (act[0] == 0x20 && poll[1] == 0x03) { - uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; - // Identifies as DESfire, use get version cmd to be sure - jbyteArray versionCmd = e->NewByteArray(5); - e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); - jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, - versionCmd, JNI_TRUE, NULL); - if (respBytes != NULL) { - // Check whether the response matches a typical DESfire - // response. - // libNFC even does more advanced checking than we do - // here, and will only format DESfire's with a certain - // major/minor sw version and NXP as a manufacturer. - // We don't want to do such checking here, to avoid - // having to change code in multiple places. - // A succesful (wrapped) DESFire getVersion command returns - // 9 bytes, with byte 7 0x91 and byte 8 having status - // code 0xAF (these values are fixed and well-known). - int respLength = e->GetArrayLength(respBytes); - jbyte* resp = e->GetByteArrayElements(respBytes, NULL); - if (respLength == 9 && resp[7] == (jbyte)0x91 && - resp[8] == (jbyte)0xAF) { - result = JNI_TRUE; - } - e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); - } - } - e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); - e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); - } - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - phNfc_sData_t keyBuffer; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_RemoteDev_FormatNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t keyBuffer; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_ConvertToReadOnlyNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeNfcTag_doDisconnect}, - {"doReconnect", "()I", - (void *)com_android_nfc_NativeNfcTag_doReconnect}, - {"doHandleReconnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, - {"doTransceive", "([BZ[I)[B", - (void *)com_android_nfc_NativeNfcTag_doTransceive}, - {"doGetNdefType", "(II)I", - (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, - {"doCheckNdef", "([I)I", - (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, - {"doRead", "()[B", - (void *)com_android_nfc_NativeNfcTag_doRead}, - {"doWrite", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doWrite}, - {"doPresenceCheck", "()Z", - (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, - {"doIsIsoDepNdefFormatable", "([B[B)Z", - (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, - {"doNdefFormat", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, - {"doMakeReadonly", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, -}; - -int register_com_android_nfc_NativeNfcTag(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp deleted file mode 100644 index b3cc6e3..0000000 --- a/jni/com_android_nfc_NativeP2pDevice.cpp +++ /dev/null @@ -1,490 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -extern uint8_t device_connected_flag; - -namespace android { - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); - -/* - * Callbacks - */ -static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presence_check_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; - psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_receive_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - *ptr = data; - } - else - { - *ptr = NULL; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Functions - */ - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - /* Report the callback data and wake up the caller */ - pCallbackData->pContext = pResBuffer; - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - jclass target_cls = NULL; - jobject tag; - jmethodID ctor; - jfieldID f; - jbyteArray generalBytes = NULL; - phNfc_sData_t sGeneralBytes; - unsigned int i; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Set General Bytes */ - target_cls = e->GetObjectClass(o); - - f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes Length = %d", sGeneralBytes.length); - TRACE("General Bytes ="); - for(i=0;iNewByteArray(sGeneralBytes.length); - - e->SetByteArrayRegion(generalBytes, 0, - sGeneralBytes.length, - (jbyte *)sGeneralBytes.buffer); - - e->SetObjectField(o, f, generalBytes); - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - /* Restart the polling loop if the connection failed */ - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jboolean result = JNI_FALSE; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Disconnect */ - TRACE("Disconnecting from target (handle = 0x%x)", handle); - - /* NativeNfcTag waits for tag to leave the field here with presence check. - * We do not in P2P path because presence check is not safe while transceive may be - * in progress. - */ - - TRACE("phLibNfc_RemoteDev_Disconnect()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); - } - else - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, - jobject o, jbyteArray data) -{ - NFCSTATUS status; - uint8_t offset = 2; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - phNfc_sData_t * receive_buffer = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) - { - goto clean_and_return; - } - - /* Transceive*/ - TRACE("Transceive data to target (handle = 0x%x)", handle); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - TRACE("Buffer Length = %d\n", buflen); - - transceive_info.sSendData.buffer = buf; //+ offset; - transceive_info.sSendData.length = buflen; //- offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(receive_buffer->length); - if(result != NULL) - e->SetByteArrayRegion(result, 0, - receive_buffer->length, - (jbyte *)receive_buffer->buffer); - -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - - -static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( - JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct timespec ts; - phLibNfc_Handle handle; - jbyteArray buf = NULL; - static phNfc_sData_t *data; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)data)) - { - goto clean_and_return; - } - - /* Receive */ - TRACE("phLibNfc_RemoteDev_Receive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(data == NULL) - { - goto clean_and_return; - } - - buf = e->NewByteArray(data->length); - e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return buf; -} - -static jboolean com_android_nfc_NativeP2pDevice_doSend( - JNIEnv *e, jobject o, jbyteArray buf) -{ - NFCSTATUS status; - phNfc_sData_t data; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Send */ - TRACE("Send data to the Initiator (handle = 0x%x)", handle); - - data.length = (uint32_t)e->GetArrayLength(buf); - data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_RemoteDev_Send()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, - {"doTransceive", "([B)[B", - (void *)com_android_nfc_NativeP2pDevice_doTransceive}, - {"doReceive", "()[B", - (void *)com_android_nfc_NativeP2pDevice_doReceive}, - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeP2pDevice_doSend}, -}; - -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", - gMethods, NELEM(gMethods)); -} - -} // namepspace android diff --git a/jni/com_android_nfc_list.cpp b/jni/com_android_nfc_list.cpp deleted file mode 100644 index f0487d3..0000000 --- a/jni/com_android_nfc_list.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#undef LOG_TAG -#define LOG_TAG "NFC_LIST" - -bool listInit(listHead* pList) -{ - pList->pFirst = NULL; - if(pthread_mutex_init(&pList->mutex, NULL) == -1) - { - ALOGE("Mutex creation failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listDestroy(listHead* pList) -{ - bool bListNotEmpty = true; - while (bListNotEmpty) { - bListNotEmpty = listGetAndRemoveNext(pList, NULL); - } - - if(pthread_mutex_destroy(&pList->mutex) == -1) - { - ALOGE("Mutex destruction failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listAdd(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pLastNode; - bool result; - - /* Create node */ - pNode = (struct listNode*)malloc(sizeof(listNode)); - if (pNode == NULL) - { - result = false; - ALOGE("Failed to malloc"); - goto clean_and_return; - } - TRACE("Allocated node: %8p (%8p)", pNode, pData); - pNode->pData = pData; - pNode->pNext = NULL; - - pthread_mutex_lock(&pList->mutex); - - /* Add the node to the list */ - if (pList->pFirst == NULL) - { - /* Set the node as the head */ - pList->pFirst = pNode; - } - else - { - /* Seek to the end of the list */ - pLastNode = pList->pFirst; - while(pLastNode->pNext != NULL) - { - pLastNode = pLastNode->pNext; - } - - /* Add the node to the current list */ - pLastNode->pNext = pNode; - } - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listRemove(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pRemovedNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst == NULL) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - pNode = pList->pFirst; - if (pList->pFirst->pData == pData) - { - /* Get the removed node */ - pRemovedNode = pNode; - - /* Remove the first node */ - pList->pFirst = pList->pFirst->pNext; - } - else - { - while (pNode->pNext != NULL) - { - if (pNode->pNext->pData == pData) - { - /* Node found ! */ - break; - } - pNode = pNode->pNext; - } - - if (pNode->pNext == NULL) - { - /* Node not found */ - result = false; - ALOGE("Failed to deallocate (not found %8p)", pData); - goto clean_and_return; - } - - /* Get the removed node */ - pRemovedNode = pNode->pNext; - - /* Remove the node from the list */ - pNode->pNext = pNode->pNext->pNext; - } - - /* Deallocate the node */ - TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); - free(pRemovedNode); - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listGetAndRemoveNext(listHead* pList, void** ppData) -{ - struct listNode* pNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - /* Work on the first node */ - pNode = pList->pFirst; - - /* Return the data */ - if (ppData != NULL) - { - *ppData = pNode->pData; - } - - /* Remove and deallocate the node */ - pList->pFirst = pNode->pNext; - TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); - free(pNode); - - result = true; - -clean_and_return: - listDump(pList); - pthread_mutex_unlock(&pList->mutex); - return result; -} - -void listDump(listHead* pList) -{ - struct listNode* pNode = pList->pFirst; - - TRACE("Node dump:"); - while (pNode != NULL) - { - TRACE("- %8p (%8p)", pNode, pNode->pData); - pNode = pNode->pNext; - } -} diff --git a/jni/com_android_nfc_list.h b/jni/com_android_nfc_list.h deleted file mode 100644 index 22b4f09..0000000 --- a/jni/com_android_nfc_list.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_LIST_H__ -#define __COM_ANDROID_NFC_LIST_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct listNode -{ - void* pData; - struct listNode* pNext; -}; - -struct listHead -{ - listNode* pFirst; - pthread_mutex_t mutex; -}; - -bool listInit(listHead* pList); -bool listDestroy(listHead* pList); -bool listAdd(listHead* pList, void* pData); -bool listRemove(listHead* pList, void* pData); -bool listGetAndRemoveNext(listHead* pList, void** ppData); -void listDump(listHead* pList); - -#ifdef __cplusplus -} -#endif - -#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/Android.mk b/nxp/Android.mk new file mode 100644 index 0000000..34f4385 --- /dev/null +++ b/nxp/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH:= $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/nxp/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/nxp/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h new file mode 100644 index 0000000..b876dad --- /dev/null +++ b/nxp/jni/com_android_nfc.h @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include +#include + +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) + #define TRACE_ENABLED 1 +#else + #define LOG_CALLBACK(...) + #define TRACE(...) + #define TRACE_ENABLED 0 +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..e6da0fa --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2623 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "com_android_nfc.h" + +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +extern uint32_t libnfc_llc_error_count; + +static phLibNfc_sConfig_t gDrvCfg; +void *gHWRef; +static phNfc_sData_t gInputParam; +static phNfc_sData_t gOutputParam; + +uint8_t device_connected_flag; +static bool driverConfigured = FALSE; + +static phLibNfc_Handle hLlcpHandle; +static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; +static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; + +static jmethodID cached_NfcManager_notifyNdefMessageListeners; +static jmethodID cached_NfcManager_notifyTransactionListeners; +static jmethodID cached_NfcManager_notifyLlcpLinkActivation; +static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; +static jmethodID cached_NfcManager_notifyTargetDeselected; + +static jmethodID cached_NfcManager_notifySeFieldActivated; +static jmethodID cached_NfcManager_notifySeFieldDeactivated; + +static jmethodID cached_NfcManager_notifySeApduReceived; +static jmethodID cached_NfcManager_notifySeMifareAccess; +static jmethodID cached_NfcManager_notifySeEmvCardRemoval; + +namespace android { + +phLibNfc_Handle storedHandle = 0; + +struct nfc_jni_native_data *exported_nat = NULL; + +/* Internal functions declaration */ +static void *nfc_jni_client_thread(void *arg); +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_se_set_mode_callback(void *context, + phLibNfc_Handle handle, NFCSTATUS status); +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status); +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); +static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); + +/* + * Deferred callback called when client thread must be exited + */ +static void client_kill_deferred_call(void* arg) +{ + struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; + + nat->running = FALSE; +} + +static void kill_client(nfc_jni_native_data *nat) +{ + phDal4Nfc_Message_Wrapper_t wrapper; + phLibNfc_DeferredCall_t *pMsg; + + usleep(50000); + + ALOGD("Terminating client thread..."); + + pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); + pMsg->pCallback = client_kill_deferred_call; + pMsg->pParameter = (void*)nat; + + wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + wrapper.msg.pMsgData = pMsg; + wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); + + phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); +} + +static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_ioctl_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_deinit_download_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) +{ + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + struct timespec ts; + NFCSTATUS status = NFCSTATUS_FAILED; + phLibNfc_StackCapabilities_t caps; + struct nfc_jni_callback_data cb_data; + bool result; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + if(update) + { + //deinit + TRACE("phLibNfc_Mgt_DeInitialize() (download)"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts)) + { + ALOGW("Deinitialization timed out (download)"); + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("Deinitialization FAILED (download)"); + } + TRACE("Deinitialization SUCCESS (download)"); + } + + result = performDownload(nat, false); + + if (!result) { + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + status = cb_data.status; + goto clean_and_return; + } + + /* ====== CAPABILITIES ======= */ + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /*Download is successful*/ + status = NFCSTATUS_SUCCESS; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return status; +} + +static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) +{ + char value[PROPERTY_VALUE_MAX]; + int result = FALSE; + NFCSTATUS status; + + /* ====== CONFIGURE DRIVER ======= */ + /* Configure hardware link */ + gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); + + TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); + REENTRANCE_UNLOCK(); + if(status == NFCSTATUS_ALREADY_INITIALISED) { + ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) + { + ALOGE("pthread_create failed"); + goto clean_and_return; + } + + driverConfigured = TRUE; + +clean_and_return: + return result; +} + +static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) +{ + int result = FALSE; + NFCSTATUS status; + + /* Unconfigure driver */ + TRACE("phLibNfc_Mgt_UnConfigureDriver()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); + } + else + { + ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = TRUE; + } + + driverConfigured = FALSE; + + return result; +} + +/* Initialization function */ +static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { + struct timespec ts; + uint8_t resp[16]; + NFCSTATUS status; + phLibNfc_StackCapabilities_t caps; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; + phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; + struct nfc_jni_callback_data cb_data; + uint8_t firmware_status; + uint8_t update = TRUE; + int result = JNI_FALSE; + const hw_module_t* hw_module; + nfc_pn544_device_t* pn544_dev = NULL; + int ret = 0; + ALOGD("Start Initialization\n"); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Get EEPROM values and device port from product-specific settings */ + ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); + if (ret) { + ALOGE("hw_get_module() failed."); + goto clean_and_return; + } + ret = nfc_pn544_open(hw_module, &pn544_dev); + if (ret) { + ALOGE("Could not open pn544 hw_module."); + goto clean_and_return; + } + if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { + ALOGE("Could not load EEPROM settings"); + goto clean_and_return; + } + + /* Reset device connected handle */ + device_connected_flag = 0; + + /* Reset stored handle */ + storedHandle = 0; + + /* Initialize Driver */ + if(!driverConfigured) + { + nfc_jni_configure_driver(nat); + } + + /* ====== INITIALIZE ======= */ + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + update = FALSE; + goto force_download; + } + TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + update = FALSE; + goto force_download; + } + + /* ====== CAPABILITIES ======= */ + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /* ====== FIRMWARE VERSION ======= */ + if(caps.psDevCapabilities.firmware_update_info) + { +force_download: + for (i=0; i<3; i++) + { + TRACE("Firmware version not UpToDate"); + status = nfc_jni_download_locked(nat, update); + if(status == NFCSTATUS_SUCCESS) + { + ALOGI("Firmware update SUCCESS"); + break; + } + ALOGW("Firmware update FAILED"); + update = FALSE; + } + if(i>=3) + { + ALOGE("Unable to update firmware, giving up"); + goto clean_and_return; + } + } + else + { + TRACE("Firmware version UpToDate"); + } + /* ====== EEPROM SETTINGS ======= */ + + // Update EEPROM settings + TRACE("****** START EEPROM SETTINGS UPDATE ******"); + for (i = 0; i < pn544_dev->num_eeprom_settings; i++) + { + char eeprom_property[PROPERTY_KEY_MAX]; + char eeprom_value[PROPERTY_VALUE_MAX]; + uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); + TRACE("> EEPROM SETTING: %d", i); + + // Check for override of this EEPROM value in properties + snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", + eeprom_base[1], eeprom_base[2]); + TRACE(">> Checking property: %s", eeprom_property); + if (property_get(eeprom_property, eeprom_value, "") == 2) { + int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); + ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", + eeprom_base[1], eeprom_base[2], eeprom_value_num); + eeprom_base[3] = eeprom_value_num; + } + + TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], + eeprom_base[3]); + gInputParam.buffer = eeprom_base; + gInputParam.length = 0x04; + gOutputParam.buffer = resp; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if (cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + } + TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); + + /* ====== SECURE ELEMENTS ======= */ + + REENTRANCE_LOCK(); + ALOGD("phLibNfc_SE_GetSecureElementList()"); + status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + + ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i < No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); + } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); + } + + /* Set SE mode - Off */ + REENTRANCE_LOCK(); + status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, + phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + } + + /* ====== LLCP ======= */ + + /* LLCP Params */ + TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); + LlcpConfigInfo.miu = nat->miu; + LlcpConfigInfo.lto = nat->lto; + LlcpConfigInfo.wks = nat->wks; + LlcpConfigInfo.option = nat->opt; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, + nfc_jni_llcpcfg_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* ===== DISCOVERY ==== */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.Duration = 300000; /* in ms */ + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== END ======= */ + + ALOGI("NFC Initialized"); + + result = TRUE; + +clean_and_return: + if (result != TRUE) + { + if(nat) + { + kill_client(nat); + } + } + if (pn544_dev != NULL) { + nfc_pn544_close(pn544_dev); + } + nfc_cb_data_deinit(&cb_data); + + return result; +} + +static int is_user_build() { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", value, ""); + return !strncmp("user", value, PROPERTY_VALUE_MAX); +} + +/* + * Last-chance fallback when there is no clean way to recover + * Performs a software reset + */ +void emergency_recovery(struct nfc_jni_native_data *nat) { + if (!is_user_build()) { + ALOGE("emergency_recovery: force restart of NFC service"); + } else { + // dont recover immediately, so we can debug + unsigned int t; + for (t=1; t < 1000000; t <<= 1) { + ALOGE("emergency_recovery: NFC stack dead-locked"); + sleep(t); + } + } + phLibNfc_Mgt_Recovery(); + abort(); // force a noisy crash +} + +void nfc_jni_reset_timeout_values() +{ + REENTRANCE_LOCK(); + phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); + phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); + phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); + phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); + REENTRANCE_UNLOCK(); +} + +/* + * Restart the polling loop when unable to perform disconnect + */ +void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) +{ + nfc_jni_start_discovery_locked(nat, true); +} + + /* + * Utility to recover UID from target infos + */ +static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + phNfc_sData_t uid; + + switch(psRemoteDevInfo->RemDevType) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_3A_PICC: + case phNfc_eMifare_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; + break; + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; + uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); + break; + case phNfc_eFelica_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; + uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; + break; + case phNfc_eJewel_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; + break; + case phNfc_eISO15693_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; + break; + case phNfc_eNfcIP1_Target: + case phNfc_eNfcIP1_Initiator: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; + uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; + break; + default: + uid.buffer = NULL; + uid.length = 0; + break; + } + + return uid; +} + +/* + * NFC stack message processing + */ +static void *nfc_jni_client_thread(void *arg) +{ + struct nfc_jni_native_data *nat; + JNIEnv *e; + JavaVMAttachArgs thread_args; + phDal4Nfc_Message_Wrapper_t wrapper; + + nat = (struct nfc_jni_native_data *)arg; + + thread_args.name = "NFC Message Loop"; + thread_args.version = nat->env_version; + thread_args.group = NULL; + + nat->vm->AttachCurrentThread(&e, &thread_args); + pthread_setname_np(pthread_self(), "message"); + + TRACE("NFC client started"); + nat->running = TRUE; + while(nat->running == TRUE) + { + /* Fetch next message from the NFC stack message queue */ + if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, + sizeof(phLibNfc_Message_t), 0, 0) == -1) + { + ALOGE("NFC client received bad message"); + continue; + } + + switch(wrapper.msg.eMsgType) + { + case PH_LIBNFC_DEFERREDCALL_MSG: + { + phLibNfc_DeferredCall_t *msg = + (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); + + REENTRANCE_LOCK(); + msg->pCallback(msg->pParameter); + REENTRANCE_UNLOCK(); + + break; + } + } + } + TRACE("NFC client stopped"); + + nat->vm->DetachCurrentThread(); + + return NULL; +} + +extern uint8_t nfc_jni_is_ndef; +extern uint8_t *nfc_jni_ndef_buf; +extern uint32_t nfc_jni_ndef_buf_len; + +static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = +{ + 3, + { 0x46, 0x66, 0x6D } +}; + +/* + * Callbacks + */ + +/* P2P - LLCP callbacks */ +static void nfc_jni_llcp_linkStatus_callback(void *pContext, + phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) +{ + phFriNfc_Llcp_sLinkParameters_t sLinkParams; + JNIEnv *e; + NFCSTATUS status; + + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; + + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + /* Update link status */ + g_eLinkStatus = eLinkStatus; + + if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) + { + REENTRANCE_LOCK(); + status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGW("GetRemote Info failded - Status = %02x",status); + } + else + { + ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, + sLinkParams.miu, + sLinkParams.option, + sLinkParams.wks); + device_connected_flag = 1; + } + } + else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) + { + ALOGI("LLCP Link deactivated"); + free(pContextData); + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Reset incoming socket list */ + while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) + { + pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); + LIST_REMOVE(pListenData, entries); + free(pListenData); + } + + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } +} + +static void nfc_jni_checkLlcp_callback(void *context, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; + + LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, + phLibNfc_Handle hIncomingSocket) +{ + phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + + /* Store the connection request */ + pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); + if (pListenData == NULL) + { + ALOGE("Failed to create structure to handle incoming LLCP connection request"); + goto clean_and_return; + } + pListenData->pServerSocket = hServiceSocket; + pListenData->pIncomingSocket = hIncomingSocket; + LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); + + /* Signal pending accept operations that the list is updated */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + +clean_and_return: + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); +} + +void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode) +{ + PHNFC_UNUSED_VARIABLE(pContext); + + TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); + + if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) + { + ALOGW("Frame Rejected - Disconnected"); + } + else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) + { + ALOGD("Socket Disconnected"); + } +} + + +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_discover_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNoOfRemoteDev) +{ + // Always prefer p2p targets over other targets. Otherwise, select the first target + // reported. + uint8_t preferred_index = 0; + for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { + if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { + preferred_index = i; + } + } + return preferred_index; +} + +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status) +{ + JNIEnv *e; + NFCSTATUS ret; + jclass tag_cls = NULL; + jobject target_array; + jobject tag; + jmethodID ctor; + jfieldID f; + const char * typeName; + jbyteArray tagUid; + jbyteArray generalBytes = NULL; + struct nfc_jni_native_data *nat; + struct timespec ts; + phNfc_sData_t data; + int i; + int target_index = 0; // Target that will be reported (if multiple can be >0) + + nat = (struct nfc_jni_native_data *)pContext; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); + + /* Notify manager that a target was deselected */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); + TRACE("Discovered %d tags", uNofRemoteDev); + + target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); + + /* Reset device connected flag */ + device_connected_flag = 1; + phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; + phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + + tag_cls = e->GetObjectClass(nat->cached_P2pDevice); + if(e->ExceptionCheck()) + { + ALOGE("Get Object Class Error"); + kill_client(nat); + return; + } + + /* New target instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID(tag_cls, "mMode", "I"); + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + ALOGD("Discovered P2P Initiator"); + e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); + } + else + { + ALOGD("Discovered P2P Target"); + e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); + } + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + /* Set General Bytes */ + f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes length ="); + for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) + { + ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); + } + + generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + + e->SetByteArrayRegion(generalBytes, 0, + remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, + (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); + + e->SetObjectField(tag, f, generalBytes); + } + + /* Set tag handle */ + f = e->GetFieldID(tag_cls, "mHandle", "I"); + e->SetIntField(tag, f,(jint)remDevHandle); + TRACE("Target handle = 0x%08x",remDevHandle); + } + else + { + tag_cls = e->GetObjectClass(nat->cached_NfcTag); + if(e->ExceptionCheck()) + { + kill_client(nat); + return; + } + + /* New tag instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + bool multi_protocol = false; + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + TRACE("Multiple Protocol TAG detected\n"); + multi_protocol = true; + } + + /* Set tag UID */ + f = e->GetFieldID(tag_cls, "mUid", "[B"); + data = get_target_uid(remDevInfo); + tagUid = e->NewByteArray(data.length); + if(data.length > 0) + { + e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); + } + e->SetObjectField(tag, f, tagUid); + + /* Generate technology list */ + jintArray techList; + jintArray handleList; + jintArray typeList; + nfc_jni_get_technology_tree(e, psRemoteDevList, + multi_protocol ? uNofRemoteDev : 1, + &techList, &handleList, &typeList); + + /* Push the technology list into the java object */ + f = e->GetFieldID(tag_cls, "mTechList", "[I"); + e->SetObjectField(tag, f, techList); + + f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); + e->SetObjectField(tag, f, handleList); + + f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField(tag, f, typeList); + + f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); + e->SetIntField(tag, f,(jint)-1); + + f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); + e->SetIntField(tag, f,(jint)-1); + } + + storedHandle = remDevHandle; + if (nat->tag != NULL) { + e->DeleteGlobalRef(nat->tag); + } + nat->tag = e->NewGlobalRef(tag); + + /* Notify the service */ + TRACE("Notify Nfc Service"); + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + /* Store the hanlde of the P2P device */ + hLlcpHandle = remDevHandle; + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + /* Notify manager that new a tag was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + e->DeleteLocalRef(tag); + } +} + +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_init_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_deinit_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Card Emulation callback */ +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) +{ + JNIEnv *e; + jobject tmp_array = NULL; + jobject mifare_block = NULL; + struct nfc_jni_native_data *nat; + phNfc_sData_t *aid; + phNfc_sData_t *mifare_command; + struct nfc_jni_callback_data *pCallbackData; + int i=0; + + LOG_CALLBACK("nfc_jni_transaction_callback", status); + + nat = (struct nfc_jni_native_data *)context; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_SUCCESS) + { + switch(evt_type) + { + case phLibNfc_eSE_EvtStartTransaction: + { + TRACE("> SE EVT_START_TRANSACTION"); + if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) + { + aid = &(evt_info->UiccEvtInfo.aid); + + ALOGD("> AID DETECTED"); + + if(aid != NULL) + { + if (TRACE_ENABLED == 1) { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + ALOGD("> AID: %s", aid_str); + } + tmp_array = e->NewByteArray(aid->length); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + goto error; + } + + TRACE("Notify Nfc Service"); + /* Notify manager that a new event occurred on a SE */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + ALOGD("> NO AID DETECTED"); + } + }break; + + case phLibNfc_eSE_EvtApduReceived: + { + phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); + TRACE("> SE EVT_APDU_RECEIVED"); + + if (apdu != NULL) { + TRACE(" APDU length=%d", apdu->length); + tmp_array = e->NewByteArray(apdu->length); + if (tmp_array == NULL) { + goto error; + } + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); + if (e->ExceptionCheck()) { + goto error; + } + } else { + TRACE(" APDU EMPTY"); + } + + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); + }break; + + case phLibNfc_eSE_EvtCardRemoval: + { + TRACE("> SE EVT_EMV_CARD_REMOVAL"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); + }break; + + case phLibNfc_eSE_EvtMifareAccess: + { + TRACE("> SE EVT_MIFARE_ACCESS"); + mifare_command = &(evt_info->UiccEvtInfo.aid); + TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); + tmp_array = e->NewByteArray(2); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); + }break; + + case phLibNfc_eSE_EvtFieldOn: + { + TRACE("> SE EVT_FIELD_ON"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); + }break; + + case phLibNfc_eSE_EvtFieldOff: + { + TRACE("> SE EVT_FIELD_OFF"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); + }break; + + default: + { + TRACE("Unknown SE event"); + }break; + } + } + else + { + ALOGE("SE transaction notification error"); + goto error; + } + + /* Function finished, now clean and return */ + goto clean_and_return; + + error: + /* In case of error, just discard the notification */ + ALOGE("Failed to send SE transaction notification"); + e->ExceptionClear(); + + clean_and_return: + if(tmp_array != NULL) + { + e->DeleteLocalRef(tmp_array); + } +} + +static void nfc_jni_se_set_mode_callback(void *pContext, + phLibNfc_Handle handle, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* + * NFCManager methods + */ + +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) +{ + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ + nfc_jni_reset_timeout_values(); + + /* Reload the p2p modes */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Start Polling loop */ + TRACE("****** Start NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, + nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + +static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) +{ + phLibNfc_sADD_Cfg_t discovery_cfg; + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + discovery_cfg.PollDevInfo.PollEnabled = 0; + discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; + discovery_cfg.NfcIP_Target_Mode = 0; + discovery_cfg.NfcIP_Tgt_Disable = TRUE; + + /* Start Polling loop */ + TRACE("****** Stop NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nfc_jni_stop_discovery_locked(nat); + + CONCURRENCY_UNLOCK(); + +} + +static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + nat = nfc_jni_get_nat(e, o); + + /* Register callback for remote device notifications. + * Must re-register every time we turn on discovery, since other operations + * (such as opening the Secure Element) can change the remote device + * notification callback*/ + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", + nat->registry_info.Jewel==TRUE?"J":"", + nat->registry_info.MifareUL==TRUE?"UL":"", + nat->registry_info.MifareStd==TRUE?"Mi":"", + nat->registry_info.Felica==TRUE?"F":"", + nat->registry_info.ISO14443_4A==TRUE?"4A":"", + nat->registry_info.ISO14443_4B==TRUE?"4B":"", + nat->registry_info.NFC==TRUE?"P2P":"", + nat->registry_info.ISO15693==TRUE?"R":"", ret); + + nfc_jni_start_discovery_locked(nat, false); +clean_and_return: + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { + CONCURRENCY_LOCK(); + nfc_jni_reset_timeout_values(); + CONCURRENCY_UNLOCK(); +} + +static void setFelicaTimeout(jint timeout) { + // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. + // It can be set to 0 to disable the timeout altogether, in which case we + // use the sw watchdog as a fallback. + if (timeout <= 255) { + phLibNfc_SetFelicaTimeout(timeout); + } else { + // Disable hw timeout, use sw watchdog for timeout + phLibNfc_SetFelicaTimeout(0); + phLibNfc_SetHciTimeout(timeout); + } + +} +// Calculates ceiling log2 of value +static unsigned int log2(int value) { + unsigned int ret = 0; + bool isPowerOf2 = ((value & (value - 1)) == 0); + while ( (value >> ret) > 1 ) ret++; + if (!isPowerOf2) ret++; + return ret; +} + +// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X +// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X +// +// We keep the constant part of the formula in a static; note the factor +// 1000 off, which is due to the fact that the formula calculates seconds, +// but this method gets milliseconds as an argument. +static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; + +static int calcTimeout(int timeout_in_ms) { + // timeout = (256 * 16 / 13560000) * 2 ^ X + // First find the first X for which timeout > requested timeout + return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); +} + +static void setIsoDepTimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + // Then re-compute the actual timeout based on X + double actual_timeout = nxp_nfc_timeout_factor * (1 << value); + // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, + // but it will take some time to get back through the sw layers. + // 500 ms should be enough). + phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); + value |= 0x10; // bit 4 to enable timeout + phLibNfc_SetIsoXchgTimeout(value); + } + else { + // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout + // must be disabled completely, to prevent the PN544 from aborting + // the transaction. We reuse the HCI sw watchdog to catch the timeout + // in that case. + phLibNfc_SetIsoXchgTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static void setNfcATimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + phLibNfc_SetMifareRawTimeout(value); + } + else { + // Disable mifare raw timeout, use HCI sw watchdog instead + phLibNfc_SetMifareRawTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, + jint tech, jint timeout) { + bool success = false; + CONCURRENCY_LOCK(); + if (timeout <= 0) { + ALOGE("Timeout must be positive."); + return false; + } else { + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + setNfcATimeout(timeout); + success = true; + break; + case TARGET_TYPE_ISO14443_4: + setIsoDepTimeout(timeout); + success = true; + break; + case TARGET_TYPE_FELICA: + setFelicaTimeout(timeout); + success = true; + break; + default: + ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); + success = false; + } + } + CONCURRENCY_UNLOCK(); + return success; +} + +static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, + jint tech) { + int timeout = -1; + CONCURRENCY_LOCK(); + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + timeout = phLibNfc_GetMifareRawTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_ISO14443_4: + timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_FELICA: + timeout = phLibNfc_GetFelicaTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Felica timeout already in ms + } + break; + default: + ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); + break; + } + CONCURRENCY_UNLOCK(); + return timeout; +} + + +static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct nfc_jni_native_data *nat = NULL; + jclass cls; + jobject obj; + jfieldID f; + + TRACE("****** Init Native Structure ******"); + + /* Initialize native structure */ + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if(nat == NULL) + { + ALOGD("malloc of nfc_jni_native_data failed"); + return FALSE; + } + memset(nat, 0, sizeof(*nat)); + e->GetJavaVM(&(nat->vm)); + nat->env_version = e->GetVersion(); + nat->manager = e->NewGlobalRef(o); + + cls = e->GetObjectClass(o); + f = e->GetFieldID(cls, "mNative", "I"); + e->SetIntField(o, f, (jint)nat); + + /* Initialize native cached references */ + cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, + "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, + "notifyTargetDeselected","()V"); + + cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, + "notifySeFieldActivated", "()V"); + + cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, + "notifySeFieldDeactivated", "()V"); + + cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + TRACE("****** Init Native Structure OK ******"); + return TRUE; + +} + +/* Init/Deinit method */ +static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + int init_result = JNI_FALSE; +#ifdef TNFC_EMULATOR_ONLY + char value[PROPERTY_VALUE_MAX]; +#endif + jboolean result; + + CONCURRENCY_LOCK(); + +#ifdef TNFC_EMULATOR_ONLY + if (!property_get("ro.kernel.qemu", value, 0)) + { + ALOGE("NFC Initialization failed: not running in an emulator\n"); + goto clean_and_return; + } +#endif + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nat->seId = SMX_SECURE_ELEMENT_ID; + + nat->lto = 150; // LLCP_LTO + nat->miu = 128; // LLCP_MIU + // WKS indicates well-known services; 1 << sap for each supported SAP. + // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) + nat->wks = 0x13; // LLCP_WKS + nat->opt = 0; // LLCP_OPT + nat->p2p_initiator_modes = phNfc_eP2P_ALL; + nat->p2p_target_modes = 0x0E; // All passive except 106, active + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; + + nat->registry_info.MifareUL = TRUE; + nat->registry_info.MifareStd = TRUE; + nat->registry_info.ISO14443_4A = TRUE; + nat->registry_info.ISO14443_4B = TRUE; + nat->registry_info.Jewel = TRUE; + nat->registry_info.Felica = TRUE; + nat->registry_info.NFC = TRUE; + nat->registry_info.ISO15693 = TRUE; + + exported_nat = nat; + + /* Perform the initialization */ + init_result = nfc_jni_initialize(nat); + +clean_and_return: + CONCURRENCY_UNLOCK(); + + /* Convert the result and return */ + return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; +} + +static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) +{ + struct timespec ts; + NFCSTATUS status; + int result = JNI_FALSE; + struct nfc_jni_native_data *nat; + int bStackReset = FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Clear previous configuration */ + memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); + memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); + + /* Create the local semaphore */ + if (nfc_cb_data_init(&cb_data, NULL)) + { + TRACE("phLibNfc_Mgt_DeInitialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status == NFCSTATUS_PENDING) + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts) == -1) + { + ALOGW("Operation timed out"); + bStackReset = TRUE; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Failed to deinit the stack"); + bStackReset = TRUE; + } + } + else + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + bStackReset = TRUE; + } + nfc_cb_data_deinit(&cb_data); + } + else + { + ALOGE("Failed to create semaphore (errno=0x%08x)", errno); + bStackReset = TRUE; + } + + kill_client(nat); + + if(bStackReset == TRUE) + { + /* Complete deinit. failed, try hard restart of NFC */ + ALOGW("Reseting stack..."); + emergency_recovery(nat); + } + + result = nfc_jni_unconfigure_driver(nat); + + TRACE("NFC Deinitialized"); + + CONCURRENCY_UNLOCK(); + + return TRUE; +} + +/* Secure Element methods */ +static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { + NFCSTATUS ret; + jintArray list= NULL; + phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; + + TRACE("****** Get Secure Element List ******"); + + TRACE("phLibNfc_SE_GetSecureElementList()"); + REENTRANCE_LOCK(); + ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_SUCCESS) { + ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + return list; + } + TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + + TRACE("Nb SE: %d", se_count); + list =e->NewIntArray(se_count); + for (i = 0; i < se_count; i++) { + if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } + e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); + } + + e->DeleteLocalRef(list); + + return list; +} + +static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Select Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Virtual */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING) { + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Deselect Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Default */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, + nfc_jni_se_set_mode_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); + if (ret != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +/* Llcp methods */ + +static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + bool freeData = false; + jboolean result = JNI_FALSE; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data *cb_data; + + + CONCURRENCY_LOCK(); + + /* Memory allocation for cb_data + * This is on the heap because it is used by libnfc + * even after this call has succesfully finished. It is only freed + * upon link closure in nfc_jni_llcp_linkStatus_callback. + */ + cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(cb_data, (void*)nat)) + { + goto clean_and_return; + } + + /* Check LLCP compliancy */ + TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, + nfc_jni_checkLlcp_callback, + nfc_jni_llcp_linkStatus_callback, + (void*)cb_data); + REENTRANCE_UNLOCK(); + /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol + * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + freeData = true; + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data->sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data->status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(cb_data); + if (freeData) { + free(cb_data); + } + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Activate(hLlcpHandle); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_FALSE; + } +} + + + +static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, + jint nSap, jstring sn) +{ + NFCSTATUS ret; + jobject connectionlessSocket = NULL; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_native_data *nat; + phNfc_sData_t sWorkingBuffer = {NULL, 0}; + phNfc_sData_t serviceName = {NULL, 0}; + phLibNfc_Llcp_sLinkParameters_t sParams; + jclass clsNativeConnectionlessSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Allocate Working buffer length */ + phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); + sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, + NULL, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + + /* Create new NativeLlcpConnectionlessSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + { + goto error; + } + + /* Get NativeConnectionless class object */ + clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); + if(e->ExceptionCheck()) + { + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); + e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); + TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); + + /* Set the miu link of the connectionless socket */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); + e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); + TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); + e->SetIntField(connectionlessSocket, f,(jint)nSap); + TRACE("Connectionless socket SAP = %d\n",nSap); + + return connectionlessSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + + if (sWorkingBuffer.buffer != NULL) { + free(sWorkingBuffer.buffer); + } + + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + phNfc_sData_t serviceName; + struct nfc_jni_native_data *nat; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + ret = phLibNfc_Llcp_Close(hLlcpSocket); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Listen( hLlcpSocket, + nfc_jni_llcp_transport_listen_socket_callback, + (void*)hLlcpSocket); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + /* Close created socket */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpServiceSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + { + ALOGE("Llcp Socket object creation error"); + goto error; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); + if(e->ExceptionCheck()) + { + ALOGE("Llcp Socket get object class error"); + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); + TRACE("Service socket Handle = %02x\n",hLlcpSocket); + + /* Set socket linear buffer length */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField(serviceSocket, f,(jint)linearBufferLength); + TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField(serviceSocket, f,(jint)miu); + TRACE("Service socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField(serviceSocket, f,(jint)rw); + TRACE("Service socket RW = %d\n",rw); + + return serviceSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + struct nfc_jni_native_data *nat; + jclass clsNativeLlcpSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + return NULL; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGE("Llcp socket object creation error"); + return NULL; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGE("Get class object error"); + return NULL; + } + + /* Test if an SAP number is present */ + if(nSap != 0) + { + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + return NULL; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField(clientSocket, f,(jint)nSap); + TRACE("socket SAP = %d\n",nSap); + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hLlcpSocket); + TRACE("socket Handle = %02x\n",hLlcpSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + TRACE("socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + TRACE("socket RW = %d\n",rw); + + + return clientSocket; +} + +static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) +{ + TRACE("Last Error Status = 0x%02x",lastErrorStatus); + + if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) + { + return ERROR_BUFFER_TOO_SMALL; + } + else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) + { + return ERROR_INSUFFICIENT_RESOURCES; + } + else + { + return lastErrorStatus; + } +} + +static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) +{ + emergency_recovery(NULL); +} + +static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting init modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_initiator_modes = modes; +} + +static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting target modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_target_modes = modes; +} + +static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { + bool result = FALSE; + int load_result; + bool wasDisabled = FALSE; + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + NFCSTATUS status = NFCSTATUS_FAILED; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + result = FALSE; + goto clean_and_return; + } + + if (takeLock) + { + CONCURRENCY_LOCK(); + } + + /* Initialize Driver */ + if(!driverConfigured) + { + result = nfc_jni_configure_driver(nat); + wasDisabled = TRUE; + } + TRACE("com_android_nfc_NfcManager_doDownload()"); + + TRACE("Go in Download Mode"); + phLibNfc_Download_Mode(); + + TRACE("Load new Firmware Image"); + load_result = phLibNfc_Load_Firmware_Image(); + if(load_result != 0) + { + TRACE("Load new Firmware Image - status = %d",load_result); + result = FALSE; + goto clean_and_return; + } + + // Download + gInputParam.buffer = InputBuffer; + gInputParam.length = 0x01; + gOutputParam.buffer = OutputBuffer; + gOutputParam.length = 0x01; + + ALOGD("Download new Firmware"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + result = FALSE; + goto clean_and_return; + } + + /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we + try to download an old-style firmware on top of a new-style + firmware. Hence, this is expected behavior, and not an + error condition. */ + if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); + } + + /*Download is successful*/ + result = TRUE; +clean_and_return: + TRACE("phLibNfc_HW_Reset()"); + phLibNfc_HW_Reset(); + /* Deinitialize Driver */ + if(wasDisabled) + { + result = nfc_jni_unconfigure_driver(nat); + } + if (takeLock) + { + CONCURRENCY_UNLOCK(); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + return performDownload(nat, true); +} + +static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); + return e->NewStringUTF(buffer); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)com_android_nfc_NfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void *)com_android_nfc_NfcManager_init_native_struc}, + + {"doInitialize", "()Z", + (void *)com_android_nfc_NfcManager_initialize}, + + {"doDeinitialize", "()Z", + (void *)com_android_nfc_NfcManager_deinitialize}, + + {"enableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)com_android_nfc_NfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)com_android_nfc_NfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)com_android_nfc_NfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)com_android_nfc_NfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)com_android_nfc_NfcManager_doAbort}, + + {"doSetP2pInitiatorModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)com_android_nfc_NfcManager_doDump}, +}; + + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e) +{ + nfc_jni_native_monitor_t *nfc_jni_native_monitor; + + nfc_jni_native_monitor = nfc_jni_init_monitor(); + if(nfc_jni_native_monitor == NULL) + { + ALOGE("NFC Manager cannot recover native monitor %x\n", errno); + return -1; + } + + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; iRemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;iNewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..f969627 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eddde94 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 602b25d..3e7a6b5 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.nxp.NativeNfcManager; -import com.android.nfc.nxp.NativeNfcSecureElement; +import com.android.nfc.dhimpl.NativeNfcManager; +import com.android.nfc.dhimpl.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; diff --git a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index c9d3b5d..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java deleted file mode 100755 index 531afd8..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java deleted file mode 100755 index a337d35..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java deleted file mode 100755 index 4bd8c24..0000000 --- a/src/com/android/nfc/nxp/NativeNfcManager.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java deleted file mode 100755 index 88f9b9d..0000000 --- a/src/com/android/nfc/nxp/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java deleted file mode 100755 index 8996dfb..0000000 --- a/src/com/android/nfc/nxp/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java deleted file mode 100755 index 7c7db41..0000000 --- a/src/com/android/nfc/nxp/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} -- cgit v1.1 From 642ab20c81425ba93e206d2a30602cd67ae8bd38 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 25 Jul 2012 13:30:11 -0700 Subject: Point jni class references to new dhimpl package. The DeviceHost classed moved to a new package, updated the JNI references accordingly. Change-Id: I11d30b241f80e2efba4570a921346ea3689b4ec5 --- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 2 +- .../com_android_nfc_NativeLlcpServiceSocket.cpp | 6 +++--- nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 2 +- nxp/jni/com_android_nfc_NativeNfcManager.cpp | 24 +++++++++++----------- nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 2 +- nxp/jni/com_android_nfc_NativeNfcTag.cpp | 2 +- nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp index 188edb4..86607b5 100644 --- a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -246,7 +246,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp index 92de3e4..2fccfc9 100644 --- a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -139,7 +139,7 @@ static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint m } /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1) { ALOGD("LLCP Socket creation error"); goto clean_and_return; @@ -209,7 +209,7 @@ static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) */ static JNINativeMethod gMethods[] = { - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void *)com_NativeLlcpServiceSocket_doAccept}, {"doClose", "()Z", @@ -220,7 +220,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", + "com/android/nfc/dhimpl/NativeLlcpServiceSocket", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp index 0c0b830..91a72a5 100644 --- a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -462,7 +462,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); + "com/android/nfc/dhimpl/NativeLlcpSocket",gMethods, NELEM(gMethods)); } } // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp index e6da0fa..d82291b 100644 --- a/nxp/jni/com_android_nfc_NativeNfcManager.cpp +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -1644,16 +1644,16 @@ static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject /* Initialize native cached references */ cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + "notifyNdefMessageListeners","(Lcom/android/nfc/dhimpl/NativeNfcTag;)V"); cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, "notifyTransactionListeners", "([B)V"); cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + "notifyLlcpLinkActivation","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, "notifyTargetDeselected","()V"); @@ -1673,13 +1673,13 @@ static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, "notifySeEmvCardRemoval", "()V"); - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeNfcTag",&(nat->cached_NfcTag)) == -1) { ALOGD("Native Structure initialization failed"); return FALSE; } - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) { ALOGD("Native Structure initialization failed"); return FALSE; @@ -2105,7 +2105,7 @@ static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEn /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) { goto error; } @@ -2232,7 +2232,7 @@ static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, j TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpServiceSocket",&(serviceSocket)) == -1) { ALOGE("Llcp Socket object creation error"); goto error; @@ -2316,7 +2316,7 @@ static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1) { ALOGE("Llcp socket object creation error"); return NULL; @@ -2566,13 +2566,13 @@ static JNINativeMethod gMethods[] = {"doActivateLlcp", "()Z", (void *)com_android_nfc_NfcManager_doActivateLlcp}, - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, {"doGetLastError", "()I", @@ -2616,7 +2616,7 @@ int register_com_android_nfc_NativeNfcManager(JNIEnv *e) } return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", + "com/android/nfc/dhimpl/NativeNfcManager", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp index bf0bffc..bb1bb2a 100755 --- a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -763,7 +763,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", + "com/android/nfc/dhimpl/NativeNfcSecureElement", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp index dbf8dc9..a621d2a 100644 --- a/nxp/jni/com_android_nfc_NativeNfcTag.cpp +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -1248,7 +1248,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeNfcTag(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", + "com/android/nfc/dhimpl/NativeNfcTag", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp index b3cc6e3..fa46052 100644 --- a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -483,7 +483,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", + "com/android/nfc/dhimpl/NativeP2pDevice", gMethods, NELEM(gMethods)); } -- cgit v1.1 From c981340b7157e1b1873ca741f37b1ff19edae0b8 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 25 Jul 2012 15:07:43 -0700 Subject: NFC: Initial NCI DeviceHost and JNI implementation. From partner drop at 07/20. Modified to fit into our new JNI/DH split. New build config that builds two targets, Nfc and NfcNci, each with their own dependencies. Product config files have to specify either Nfc or NfcNci in their packages config. Change-Id: I348a3aad7167195ca03baf9636408ab8e4c55fce --- Android.mk | 35 +- nci/Android.mk | 3 + nci/jni/Android.mk | 47 + nci/jni/CondVar.cpp | 136 ++ nci/jni/CondVar.h | 82 + nci/jni/DataQueue.cpp | 146 ++ nci/jni/DataQueue.h | 97 + nci/jni/HostAidRouter.cpp | 281 +++ nci/jni/HostAidRouter.h | 147 ++ nci/jni/IntervalTimer.cpp | 90 + nci/jni/IntervalTimer.h | 29 + nci/jni/Mutex.cpp | 127 ++ nci/jni/Mutex.h | 93 + nci/jni/NativeLlcpConnectionlessSocket.cpp | 313 +++ nci/jni/NativeLlcpServiceSocket.cpp | 162 ++ nci/jni/NativeLlcpSocket.cpp | 274 +++ nci/jni/NativeNfcManager.cpp | 1686 +++++++++++++++ nci/jni/NativeNfcTag.cpp | 1554 ++++++++++++++ nci/jni/NativeP2pDevice.cpp | 95 + nci/jni/NativeSecureElement.cpp | 221 ++ nci/jni/NfcJniUtil.cpp | 151 ++ nci/jni/NfcJniUtil.h | 159 ++ nci/jni/NfcTag.cpp | 1229 +++++++++++ nci/jni/NfcTag.h | 357 ++++ nci/jni/PeerToPeer.cpp | 2158 ++++++++++++++++++++ nci/jni/PeerToPeer.h | 705 +++++++ nci/jni/PowerSwitch.cpp | 410 ++++ nci/jni/PowerSwitch.h | 236 +++ nci/jni/RouteDataSet.cpp | 546 +++++ nci/jni/RouteDataSet.h | 299 +++ nci/jni/SecureElement.cpp | 1987 ++++++++++++++++++ nci/jni/SecureElement.h | 560 +++++ nci/jni/SyncEvent.h | 167 ++ .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 + .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 + .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 385 ++++ .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 + nci/src/com/android/nfc/dhimpl/NativeNfcTag.java | 811 ++++++++ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 22 + src/com/android/nfc/DeviceHost.java | 4 + src/com/android/nfc/NfcService.java | 24 +- 43 files changed, 16179 insertions(+), 23 deletions(-) create mode 100644 nci/Android.mk create mode 100644 nci/jni/Android.mk create mode 100644 nci/jni/CondVar.cpp create mode 100644 nci/jni/CondVar.h create mode 100644 nci/jni/DataQueue.cpp create mode 100644 nci/jni/DataQueue.h create mode 100644 nci/jni/HostAidRouter.cpp create mode 100644 nci/jni/HostAidRouter.h create mode 100644 nci/jni/IntervalTimer.cpp create mode 100644 nci/jni/IntervalTimer.h create mode 100644 nci/jni/Mutex.cpp create mode 100644 nci/jni/Mutex.h create mode 100644 nci/jni/NativeLlcpConnectionlessSocket.cpp create mode 100644 nci/jni/NativeLlcpServiceSocket.cpp create mode 100644 nci/jni/NativeLlcpSocket.cpp create mode 100755 nci/jni/NativeNfcManager.cpp create mode 100755 nci/jni/NativeNfcTag.cpp create mode 100644 nci/jni/NativeP2pDevice.cpp create mode 100755 nci/jni/NativeSecureElement.cpp create mode 100755 nci/jni/NfcJniUtil.cpp create mode 100755 nci/jni/NfcJniUtil.h create mode 100755 nci/jni/NfcTag.cpp create mode 100755 nci/jni/NfcTag.h create mode 100644 nci/jni/PeerToPeer.cpp create mode 100644 nci/jni/PeerToPeer.h create mode 100755 nci/jni/PowerSwitch.cpp create mode 100755 nci/jni/PowerSwitch.h create mode 100644 nci/jni/RouteDataSet.cpp create mode 100644 nci/jni/RouteDataSet.h create mode 100755 nci/jni/SecureElement.cpp create mode 100755 nci/jni/SecureElement.h create mode 100644 nci/jni/SyncEvent.h create mode 100755 nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeNfcManager.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeNfcTag.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index 2cdfc68..9aa7ee2 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,8 @@ LOCAL_PATH:= $(call my-dir) + +######################################## +# NXP Configuration +######################################## include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional @@ -6,13 +10,8 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) -ifeq ($(NFC_USE_NCI_STACK), true) - LOCAL_SRC_FILES += \ - $(call all-java-files-under, nci) -else - LOCAL_SRC_FILES += \ +LOCAL_SRC_FILES += \ $(call all-java-files-under, nxp) -endif LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform @@ -25,6 +24,30 @@ LOCAL_PROGUARD_ENABLED := disabled include $(BUILD_PACKAGE) +######################################## +# NCI Configuration +######################################## +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) + +LOCAL_SRC_FILES += \ + $(call all-java-files-under, nci) + +LOCAL_PACKAGE_NAME := NfcNci +LOCAL_OVERRIDES_PACKAGES := Nfc +LOCAL_CERTIFICATE := platform + +LOCAL_STATIC_JAVA_LIBRARIES := NfcLogTags + +LOCAL_JNI_SHARED_LIBRARIES := libnfc_nci_jni + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) ##### # static lib for the log tags diff --git a/nci/Android.mk b/nci/Android.mk new file mode 100644 index 0000000..34f4385 --- /dev/null +++ b/nci/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH:= $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk new file mode 100644 index 0000000..a1fb83e --- /dev/null +++ b/nci/jni/Android.mk @@ -0,0 +1,47 @@ +VOB_COMPONENTS := external/libnfc-nci/src +NFA := $(VOB_COMPONENTS)/nfa +NFC := $(VOB_COMPONENTS)/nfc + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false + +ifneq ($(NCI_VERSION),) +LOCAL_CFLAGS += -DNCI_VERSION=$(NCI_VERSION) -O0 -g +endif + +define all-cpp-files-under +$(patsubst ./%,%, \ + $(shell cd $(LOCAL_PATH) ; \ + find $(1) -name "*.cpp" -and -not -name ".*") \ + ) +endef + +LOCAL_SRC_FILES:= $(call all-cpp-files-under, .) + +LOCAL_C_INCLUDES += \ + external/astl/include \ + external/libxml2/include \ + external/icu4c/common \ + $(NFA)/include \ + $(NFA)/brcm \ + $(NFC)/include \ + $(NFC)/brcm \ + $(NFC)/int \ + $(VOB_COMPONENTS)/include \ + $(VOB_COMPONENTS)/gki/ulinux \ + $(VOB_COMPONENTS)/gki/common + +LOCAL_SHARED_LIBRARIES := \ + libicuuc \ + libnativehelper \ + libcutils \ + libutils \ + libnfc-nci + +LOCAL_STATIC_LIBRARIES := libxml2 + +LOCAL_MODULE := libnfc_nci_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nci/jni/CondVar.cpp b/nci/jni/CondVar.cpp new file mode 100644 index 0000000..cb67825 --- /dev/null +++ b/nci/jni/CondVar.cpp @@ -0,0 +1,136 @@ +/***************************************************************************** +** +** Name: CondVar.cpp +** +** Description: Encapsulate a condition variable for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "CondVar.h" +#include "NfcJniUtil.h" +#include + + +/******************************************************************************* +** +** Function: CondVar +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +CondVar::CondVar () +{ + memset (&mCondition, 0, sizeof(mCondition)); + int const res = pthread_cond_init (&mCondition, NULL); + if (res) + { + ALOGE ("CondVar::CondVar: fail init; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: ~CondVar +** +** Description: Cleanup all resources. +** +** Returns: None. +** +*******************************************************************************/ +CondVar::~CondVar () +{ + int const res = pthread_cond_destroy (&mCondition); + if (res) + { + ALOGE ("CondVar::~CondVar: fail destroy; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: wait +** +** Description: Block the caller and wait for a condition. +** +** Returns: None. +** +*******************************************************************************/ +void CondVar::wait (Mutex& mutex) +{ + int const res = pthread_cond_wait (&mCondition, mutex.nativeHandle()); + if (res) + { + ALOGE ("CondVar::wait: fail wait; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: wait +** +** Description: Block the caller and wait for a condition. +** millisec: Timeout in milliseconds. +** +** Returns: True if wait is successful; false if timeout occurs. +** +*******************************************************************************/ +bool CondVar::wait (Mutex& mutex, long millisec) +{ + bool retVal = false; + struct timespec absoluteTime; + + if (clock_gettime (CLOCK_MONOTONIC, &absoluteTime) == -1) + { + ALOGE ("CondVar::wait: fail get time; errno=0x%X", errno); + } + else + { + absoluteTime.tv_sec += millisec / 1000; + long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000); + if (ns > 1000000000) + { + absoluteTime.tv_sec++; + absoluteTime.tv_nsec = ns - 1000000000; + } + else + absoluteTime.tv_nsec = ns; + } + + //pthread_cond_timedwait_monotonic_np() is an Android-specific function + //declared in /development/ndk/platforms/android-9/include/pthread.h; + //it uses monotonic clock. + //the standard pthread_cond_timedwait() uses realtime clock. + int waitResult = pthread_cond_timedwait_monotonic_np (&mCondition, mutex.nativeHandle(), &absoluteTime); + if ((waitResult != 0) && (waitResult != ETIMEDOUT)) + ALOGE ("CondVar::wait: fail timed wait; error=0x%X", waitResult); + retVal = (waitResult == 0); //waited successfully + return retVal; +} + + +/******************************************************************************* +** +** Function: notifyOne +** +** Description: Unblock the waiting thread. +** +** Returns: None. +** +*******************************************************************************/ +void CondVar::notifyOne () +{ + int const res = pthread_cond_signal (&mCondition); + if (res) + { + ALOGE ("CondVar::notifyOne: fail signal; error=0x%X", res); + } +} + diff --git a/nci/jni/CondVar.h b/nci/jni/CondVar.h new file mode 100644 index 0000000..bfe4dfb --- /dev/null +++ b/nci/jni/CondVar.h @@ -0,0 +1,82 @@ +/***************************************************************************** +** +** Name: CondVar.h +** +** Description: Encapsulate a condition variable for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include +#include "Mutex.h" + + +class CondVar +{ +public: + /******************************************************************************* + ** + ** Function: CondVar + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + CondVar (); + + + /******************************************************************************* + ** + ** Function: ~CondVar + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~CondVar (); + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the caller and wait for a condition. + ** + ** Returns: None. + ** + *******************************************************************************/ + void wait (Mutex& mutex); + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the caller and wait for a condition. + ** millisec: Timeout in milliseconds. + ** + ** Returns: True if wait is successful; false if timeout occurs. + ** + *******************************************************************************/ + bool wait (Mutex& mutex, long millisec); + + + /******************************************************************************* + ** + ** Function: notifyOne + ** + ** Description: Unblock the waiting thread. + ** + ** Returns: None. + ** + *******************************************************************************/ + void notifyOne (); + +private: + pthread_cond_t mCondition; +}; \ No newline at end of file diff --git a/nci/jni/DataQueue.cpp b/nci/jni/DataQueue.cpp new file mode 100644 index 0000000..2b07c7e --- /dev/null +++ b/nci/jni/DataQueue.cpp @@ -0,0 +1,146 @@ +/***************************************************************************** +** +** Name: DataQueue.cpp +** +** Description: Store data bytes in a variable-size queue. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "DataQueue.h" + + +/******************************************************************************* +** +** Function: DataQueue +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +DataQueue::DataQueue () +{ +} + + +/******************************************************************************* +** +** Function: ~DataQueue +** +** Description: Release all resources. +** +** Returns: None. +** +*******************************************************************************/ +DataQueue::~DataQueue () +{ + mMutex.lock (); + while (mQueue.empty() == false) + { + tHeader* header = mQueue.front (); + mQueue.pop_front (); + free (header); + } + mMutex.unlock (); +} + + +bool DataQueue::isEmpty() +{ + mMutex.lock (); + bool retval = mQueue.empty(); + mMutex.unlock (); + return retval; +} + + +/******************************************************************************* +** +** Function: enqueue +** +** Description: Append data to the queue. +** data: array of bytes +** dataLen: length of the data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool DataQueue::enqueue (UINT8* data, UINT16 dataLen) +{ + if ((data == NULL) || (dataLen==0)) + return false; + + mMutex.lock (); + + bool retval = false; + tHeader* header = (tHeader*) malloc (sizeof(tHeader) + dataLen); + + if (header) + { + memset (header, 0, sizeof(tHeader)); + header->mDataLen = dataLen; + memcpy (header+1, data, dataLen); + + mQueue.push_back (header); + + retval = true; + } + else + { + ALOGE ("DataQueue::enqueue: out of memory ?????"); + } + mMutex.unlock (); + return retval; +} + + +/******************************************************************************* +** +** Function: dequeue +** +** Description: Retrieve and remove data from the front of the queue. +** buffer: array to store the data. +** bufferMaxLen: maximum size of the buffer. +** actualLen: actual length of the data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool DataQueue::dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen) +{ + mMutex.lock (); + + tHeader* header = mQueue.front (); + bool retval = false; + + if (header && buffer && (bufferMaxLen>0)) + { + if (header->mDataLen <= bufferMaxLen) + { + //caller's buffer is big enough to store all data + actualLen = header->mDataLen; + char* src = (char*)(header) + sizeof(tHeader) + header->mOffset; + memcpy (buffer, src, actualLen); + + mQueue.pop_front (); + free (header); + } + else + { + //caller's buffer is too small + actualLen = bufferMaxLen; + char* src = (char*)(header) + sizeof(tHeader) + header->mOffset; + memcpy (buffer, src, actualLen); + //adjust offset so the next dequeue() will get the remainder + header->mDataLen -= actualLen; + header->mOffset += actualLen; + } + retval = true; + } + mMutex.unlock (); + return retval; +} + diff --git a/nci/jni/DataQueue.h b/nci/jni/DataQueue.h new file mode 100644 index 0000000..4c0c454 --- /dev/null +++ b/nci/jni/DataQueue.h @@ -0,0 +1,97 @@ +/***************************************************************************** +** +** Name: DataQueue.h +** +** Description: Store data bytes in a variable-size queue. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include "NfcJniUtil.h" +#include "gki.h" +#include "Mutex.h" +#include + + +class DataQueue +{ +public: + /******************************************************************************* + ** + ** Function: DataQueue + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + DataQueue (); + + + /******************************************************************************* + ** + ** Function: ~DataQueue + ** + ** Description: Release all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~DataQueue (); + + + /******************************************************************************* + ** + ** Function: enqueue + ** + ** Description: Append data to the queue. + ** data: array of bytes + ** dataLen: length of the data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool enqueue (UINT8* data, UINT16 dataLen); + + + /******************************************************************************* + ** + ** Function: dequeue + ** + ** Description: Retrieve and remove data from the front of the queue. + ** buffer: array to store the data. + ** bufferMaxLen: maximum size of the buffer. + ** actualLen: actual length of the data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen); + + + /******************************************************************************* + ** + ** Function: isEmpty + ** + ** Description: Whether the queue is empty. + ** + ** Returns: True if empty. + ** + *******************************************************************************/ + bool isEmpty(); + +private: + struct tHeader + { + UINT16 mDataLen; //number of octets of data + UINT16 mOffset; //offset of the first octet of data + }; + typedef std::list Queue; + + Queue mQueue; + Mutex mMutex; +}; + diff --git a/nci/jni/HostAidRouter.cpp b/nci/jni/HostAidRouter.cpp new file mode 100644 index 0000000..dd54d19 --- /dev/null +++ b/nci/jni/HostAidRouter.cpp @@ -0,0 +1,281 @@ +/***************************************************************************** +** +** Name: HostAidRouter.cpp +** +** Description: Manage listen-mode AID routing to the host. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include "HostAidRouter.h" +#include "config.h" +#include "SecureElement.h" + + +HostAidRouter HostAidRouter::sHostAidRouter; //singleton HostAidRouter object + + +/******************************************************************************* +** +** Function: HostAidRouter +** +** Description: Private constructor to prevent public call. +** +** Returns: None. +** +*******************************************************************************/ +HostAidRouter::HostAidRouter () + : mTempHandle (NFA_HANDLE_INVALID), + mIsFeatureEnabled (true) +{ +} + + +/******************************************************************************* +** +** Function: ~HostAidRouter +** +** Description: Private destructor to prevent public call. +** +** Returns: None. +** +*******************************************************************************/ +HostAidRouter::~HostAidRouter () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Obtain a reference to the singleton object of HostAidRouter +** +** Returns: Reference to HostAidRouter object. +** +*******************************************************************************/ +HostAidRouter& HostAidRouter::getInstance () +{ + return sHostAidRouter; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize all resources. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::initialize () +{ + unsigned long num = 0; + mTempHandle = NFA_HANDLE_INVALID; + mHandleDatabase.clear (); + + if (GetNumValue (NAME_REGISTER_VIRTUAL_SE, &num, sizeof (num))) + mIsFeatureEnabled = num != 0; + return true; +} + + +/******************************************************************************* +** +** Function: addPpseRoute +** +** Description: Route Proximity Payment System Environment request +** to the host. This function is called when there is no +** route data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::addPpseRoute () +{ + static const char fn [] = "HostAidRouter::addPpseRoute"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsFeatureEnabled) + { + ALOGD ("%s: feature disabled", fn); + goto TheEnd; + } + + { + ALOGD ("%s: register PPSE AID", fn); + SyncEventGuard guard (mRegisterEvent); + mTempHandle = NFA_HANDLE_INVALID; + nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) "2PAY.SYS.DDF01", 14, stackCallback); + if (nfaStat == NFA_STATUS_OK) + { + mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT + if (mTempHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: received invalid handle", fn); + goto TheEnd; + } + else + mHandleDatabase.push_back (mTempHandle); + } + else + { + ALOGE ("%s: fail register", fn); + goto TheEnd; + } + } + retval = true; + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: deleteAllRoutes +** +** Description: Delete all AID routes to the host. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::deleteAllRoutes () +{ + static const char fn [] = "HostAidRouter::deleteAllRoutes"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsFeatureEnabled) + { + ALOGD ("%s: feature disabled", fn); + goto TheEnd; + } + + //deregister each registered AID from the stack + for (AidHandleDatabase::iterator iter1 = mHandleDatabase.begin(); iter1 != mHandleDatabase.end(); iter1++) + { + tNFA_HANDLE aidHandle = *iter1; + ALOGD ("%s: deregister h=0x%X", fn, aidHandle); + SyncEventGuard guard (mDeregisterEvent); + nfaStat = NFA_CeDeregisterAidOnDH (aidHandle); + if (nfaStat == NFA_STATUS_OK) + mDeregisterEvent.wait (); //wait for NFA_CE_DEREGISTERED_EVT + else + ALOGE ("%s: fail deregister", fn); + } + mHandleDatabase.clear (); + retval = true; + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: startRoute +** +** Description: Begin to route AID request to the host. +** aid: Buffer that contains Application ID +** aidLen: Actual length of the buffer. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::startRoute (const UINT8* aid, UINT8 aidLen) +{ + static const char fn [] = "HostAidRouter::startRoute"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsFeatureEnabled) + { + ALOGD ("%s: feature disabled", fn); + goto TheEnd; + } + + { + ALOGD ("%s: register AID; len=%u", fn, aidLen); + SyncEventGuard guard (mRegisterEvent); + mTempHandle = NFA_HANDLE_INVALID; + nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) aid, aidLen, stackCallback); + if (nfaStat == NFA_STATUS_OK) + { + mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT + if (mTempHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: received invalid handle", fn); + goto TheEnd; + } + else + mHandleDatabase.push_back (mTempHandle); + } + else + { + ALOGE ("%s: fail register", fn); + goto TheEnd; + } + } + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: stackCallback +** +** Description: Receive events from the NFC stack. +** +** Returns: None. +** +*******************************************************************************/ +void HostAidRouter::stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + static const char fn [] = "HostAidRouter::stackCallback"; + ALOGD("%s: event=0x%X", fn, event); + + switch (event) + { + case NFA_CE_REGISTERED_EVT: + { + tNFA_CE_REGISTERED& ce_registered = eventData->ce_registered; + ALOGD("%s: NFA_CE_REGISTERED_EVT; status=0x%X; h=0x%X", fn, ce_registered.status, ce_registered.handle); + SyncEventGuard guard (sHostAidRouter.mRegisterEvent); + if (ce_registered.status == NFA_STATUS_OK) + sHostAidRouter.mTempHandle = ce_registered.handle; + else + sHostAidRouter.mTempHandle = NFA_HANDLE_INVALID; + sHostAidRouter.mRegisterEvent.notifyOne(); + } + break; + + case NFA_CE_DEREGISTERED_EVT: + { + tNFA_CE_DEREGISTERED& ce_deregistered = eventData->ce_deregistered; + ALOGD("%s: NFA_CE_DEREGISTERED_EVT; h=0x%X", fn, ce_deregistered.handle); + SyncEventGuard guard (sHostAidRouter.mDeregisterEvent); + sHostAidRouter.mDeregisterEvent.notifyOne(); + } + break; + + case NFA_CE_DATA_EVT: + { + tNFA_CE_DATA& ce_data = eventData->ce_data; + ALOGD("%s: NFA_CE_DATA_EVT; h=0x%X; data len=%u", fn, ce_data.handle, ce_data.len); + SecureElement::getInstance().notifyTransactionListenersOfAid ((UINT8 *)"2PAY.SYS.DDF01", 14); + } + break; + } +} diff --git a/nci/jni/HostAidRouter.h b/nci/jni/HostAidRouter.h new file mode 100644 index 0000000..409df93 --- /dev/null +++ b/nci/jni/HostAidRouter.h @@ -0,0 +1,147 @@ +/***************************************************************************** +** +** Name: HostAidRouter.h +** +** Description: Manage listen-mode AID routing to the host. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "SyncEvent.h" +#include "NfcJniUtil.h" +#include "RouteDataSet.h" +#include +extern "C" +{ + #include "nfa_api.h" +} + + +class HostAidRouter +{ +public: + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Obtain a reference to the singleton object of HostAidRouter + ** + ** Returns: Reference to HostAidRouter object. + ** + *******************************************************************************/ + static HostAidRouter& getInstance (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize all resources. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool initialize (); + + + /******************************************************************************* + ** + ** Function: addPpseRoute + ** + ** Description: Route Proximity Payment System Environment request + ** to the host. This function is called when there is no + ** route data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool addPpseRoute (); + + + /******************************************************************************* + ** + ** Function: deleteAllRoutes + ** + ** Description: Delete all AID routes to the host. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool deleteAllRoutes (); + + + /******************************************************************************* + ** + ** Function: isFeatureEnabled + ** + ** Description: Is AID-routing-to-host feature enabled? + ** + ** Returns: True if enabled. + ** + *******************************************************************************/ + bool isFeatureEnabled () {return mIsFeatureEnabled;}; + + + /******************************************************************************* + ** + ** Function: startRoute + ** + ** Description: Begin to route AID request to the host. + ** aid: Buffer that contains Application ID + ** aidLen: Actual length of the buffer. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool startRoute (const UINT8* aid, UINT8 aidLen); + + +private: + typedef std::vector AidHandleDatabase; + + tNFA_HANDLE mTempHandle; + bool mIsFeatureEnabled; + static HostAidRouter sHostAidRouter; //singleton object + RouteDataSet mRouteDataSet; //route data from xml file + SyncEvent mRegisterEvent; + SyncEvent mDeregisterEvent; + AidHandleDatabase mHandleDatabase; //store all AID handles that are registered with the stack + + + /******************************************************************************* + ** + ** Function: HostAidRouter + ** + ** Description: Private constructor to prevent public call. + ** + ** Returns: None. + ** + *******************************************************************************/ + HostAidRouter (); + + + /******************************************************************************* + ** + ** Function: ~HostAidRouter + ** + ** Description: Private destructor to prevent public call. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~HostAidRouter (); + + + /******************************************************************************* + ** + ** Function: stackCallback + ** + ** Description: Receive events from the NFC stack. + ** + ** Returns: None. + ** + *******************************************************************************/ + static void stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventdata); +}; diff --git a/nci/jni/IntervalTimer.cpp b/nci/jni/IntervalTimer.cpp new file mode 100644 index 0000000..4cca01a --- /dev/null +++ b/nci/jni/IntervalTimer.cpp @@ -0,0 +1,90 @@ +/***************************************************************************** +** +** Name: IntervalTimer.cpp +** +** Description: Asynchronous interval timer. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "IntervalTimer.h" +#include + + +IntervalTimer::IntervalTimer() +{ + mTimerId = NULL; + mCb = NULL; +} + + +bool IntervalTimer::set(int ms, TIMER_FUNC cb) +{ + if (mTimerId == NULL) + { + if (cb == NULL) + return false; + + if (!create(cb)) + return false; + } + if (cb != mCb) + { + kill(); + if (!create(cb)) + return false; + } + + int stat = 0; + struct itimerspec ts; + ts.it_value.tv_sec = ms / 1000; + ts.it_value.tv_nsec = (ms % 1000) * 1000000; + + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + stat = timer_settime(mTimerId, 0, &ts, 0); + if (stat == -1) + ALOGE("IntervalTimer::set: fail set timer"); + return stat == 0; +} + + +IntervalTimer::~IntervalTimer() +{ + kill(); +} + + +void IntervalTimer::kill() +{ + if (mTimerId == NULL) + return; + + timer_delete(mTimerId); + mTimerId = NULL; + mCb = NULL; +} + + +bool IntervalTimer::create(TIMER_FUNC cb) +{ + struct sigevent se; + int stat = 0; + + /* + * Set the sigevent structure to cause the signal to be + * delivered by creating a new thread. + */ + se.sigev_notify = SIGEV_THREAD; + se.sigev_value.sival_ptr = &mTimerId; + se.sigev_notify_function = cb; + se.sigev_notify_attributes = NULL; + mCb = cb; + stat = timer_create(CLOCK_MONOTONIC, &se, &mTimerId); + if (stat == -1) + ALOGE("IntervalTimer::create: fail create timer"); + return stat == 0; +} diff --git a/nci/jni/IntervalTimer.h b/nci/jni/IntervalTimer.h new file mode 100644 index 0000000..0f1095f --- /dev/null +++ b/nci/jni/IntervalTimer.h @@ -0,0 +1,29 @@ +/***************************************************************************** +** +** Name: IntervalTimer.h +** +** Description: Asynchronous interval timer. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include + + +class IntervalTimer +{ +public: + typedef void (*TIMER_FUNC) (union sigval); + + IntervalTimer(); + ~IntervalTimer(); + bool set(int ms, TIMER_FUNC cb); + void kill(); + bool create(TIMER_FUNC ); + +private: + timer_t mTimerId; + TIMER_FUNC mCb; +}; diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp new file mode 100644 index 0000000..4034a03 --- /dev/null +++ b/nci/jni/Mutex.cpp @@ -0,0 +1,127 @@ +/***************************************************************************** +** +** Name: Mutex.cpp +** +** Description: Encapsulate a mutex for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "Mutex.h" +#include "NfcJniUtil.h" +#include + +/******************************************************************************* +** +** Function: Mutex +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +Mutex::Mutex () +{ + memset (&mMutex, 0, sizeof(mMutex)); + int res = pthread_mutex_init (&mMutex, NULL); + if (res != 0) + { + ALOGE ("Mutex::Mutex: fail init; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: ~Mutex +** +** Description: Cleanup all resources. +** +** Returns: None. +** +*******************************************************************************/ +Mutex::~Mutex () +{ + int res = pthread_mutex_destroy (&mMutex); + if (res != 0) + { + ALOGE ("Mutex::~Mutex: fail destroy; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: lock +** +** Description: Block the thread and try lock the mutex. +** +** Returns: None. +** +*******************************************************************************/ +void Mutex::lock () +{ + int res = pthread_mutex_lock (&mMutex); + if (res != 0) + { + ALOGE ("Mutex::lock: fail lock; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: unlock +** +** Description: Unlock a mutex to unblock a thread. +** +** Returns: None. +** +*******************************************************************************/ +void Mutex::unlock () +{ + int res = pthread_mutex_unlock (&mMutex); + if (res != 0) + { + ALOGE ("Mutex::lock: fail unlock; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: tryLock +** +** Description: Try to lock the mutex. +** +** Returns: True if the mutex is locked. +** +*******************************************************************************/ +bool Mutex::tryLock () +{ + int res = pthread_mutex_trylock (&mMutex); + if ((res != 0) && (res != EBUSY)) + { + ALOGE ("Mutex::lock: fail try-lock; error=0x%X", res); + } + return res == 0; +} + + +/******************************************************************************* +** +** Function: nativeHandle +** +** Description: Get the handle of the mutex. +** +** Returns: Handle of the mutex. +** +*******************************************************************************/ +pthread_mutex_t* Mutex::nativeHandle () +{ + return &mMutex; +} + + diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h new file mode 100644 index 0000000..c858e8e --- /dev/null +++ b/nci/jni/Mutex.h @@ -0,0 +1,93 @@ +/***************************************************************************** +** +** Name: Mutex.h +** +** Description: Encapsulate a mutex for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include + + +class Mutex +{ +public: + /******************************************************************************* + ** + ** Function: Mutex + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + Mutex (); + + + /******************************************************************************* + ** + ** Function: ~Mutex + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~Mutex (); + + + /******************************************************************************* + ** + ** Function: lock + ** + ** Description: Block the thread and try lock the mutex. + ** + ** Returns: None. + ** + *******************************************************************************/ + void lock (); + + + /******************************************************************************* + ** + ** Function: unlock + ** + ** Description: Unlock a mutex to unblock a thread. + ** + ** Returns: None. + ** + *******************************************************************************/ + void unlock (); + + + /******************************************************************************* + ** + ** Function: tryLock + ** + ** Description: Try to lock the mutex. + ** + ** Returns: True if the mutex is locked. + ** + *******************************************************************************/ + bool tryLock (); + + + /******************************************************************************* + ** + ** Function: nativeHandle + ** + ** Description: Get the handle of the mutex. + ** + ** Returns: Handle of the mutex. + ** + *******************************************************************************/ + pthread_mutex_t* nativeHandle (); + +private: + pthread_mutex_t mMutex; +}; + diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..88361a6 --- /dev/null +++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "NfcJniUtil.h" +extern "C" +{ + #include "nfa_api.h" + #include "nfa_p2p_api.h" +} + + +namespace android +{ + + +extern char* gNativeLlcpConnectionlessSocketClassName; + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ +static sem_t sConnlessRecvSem; +static jboolean sConnlessRecvWaitingForData = JNI_FALSE; +static uint8_t* sConnlessRecvBuf = NULL; +static uint32_t sConnlessRecvLen = 0; +static uint32_t sConnlessRecvRemoteSap = 0; + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_doSendTo +** +** Description: Send data to peer. +** e: JVM environment. +** o: Java object. +** nsap: service access point. +** data: buffer for data. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + jint handle = 0; + uint8_t* buf = NULL; + uint32_t len = 0; + jclass c = NULL; + jfieldID f = NULL; + + ALOGD ("%s: nsap = %d", __FUNCTION__, nsap); + + c = e->GetObjectClass (o); + f = e->GetFieldID (c, "mHandle", "I"); + handle = e->GetIntField (o, f); + + buf = (uint8_t*) e->GetByteArrayElements (data, NULL); + len = (uint32_t) e->GetArrayLength (data); + + ALOGD ("NFA_P2pSendUI: len = %d", len); + status = NFA_P2pSendUI ((tNFA_HANDLE) handle, nsap, len, buf); + + ALOGD ("%s: NFA_P2pSendUI done, status = %d", __FUNCTION__, status); + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_P2pSendUI failed, status = %d", __FUNCTION__, status); + return JNI_FALSE; + } + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_receiveData +** +** Description: Receive data from the stack. +** data: buffer contains data. +** len: length of data. +** remoteSap: remote service access point. +** +** Returns: None +** +*******************************************************************************/ +void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remoteSap) +{ + ALOGD ("%s: waiting for data = %d, len = %d", __FUNCTION__, sConnlessRecvWaitingForData, len); + + // Sanity... + if (sConnlessRecvLen < len) + { + len = sConnlessRecvLen; + } + + if (sConnlessRecvWaitingForData) + { + sConnlessRecvWaitingForData = JNI_FALSE; + sConnlessRecvLen = len; + memcpy (sConnlessRecvBuf, data, len); + sConnlessRecvRemoteSap = remoteSap; + + sem_post (&sConnlessRecvSem); + } +} + + +/******************************************************************************* +** +** Function: connectionlessCleanup +** +** Description: Free resources. +** +** Returns: None +** +*******************************************************************************/ +static jobject connectionlessCleanup () +{ + sConnlessRecvWaitingForData = JNI_FALSE; + sConnlessRecvLen = 0; + if (sConnlessRecvBuf != NULL) + { + free (sConnlessRecvBuf); + sConnlessRecvBuf = NULL; + } + return NULL; +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_abortWait +** +** Description: Abort current operation and unblock threads. +** +** Returns: None +** +*******************************************************************************/ +void nativeLlcpConnectionlessSocket_abortWait () +{ + sem_post (&sConnlessRecvSem); +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_doReceiveFrom +** +** Description: Receive data from a peer. +** e: JVM environment. +** o: Java object. +** linkMiu: max info unit +** +** Returns: LlcpPacket Java object. +** +*******************************************************************************/ +static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv *e, jobject o, jint linkMiu) +{ + jbyteArray receivedData = NULL; + jobject llcpPacket = NULL; + jclass clsLlcpPacket = NULL; + jfieldID f = NULL; + + ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu); + + if (sConnlessRecvWaitingForData != JNI_FALSE) + { + ALOGD ("%s: Already waiting for incoming data", __FUNCTION__); + return NULL; + } + + sConnlessRecvBuf = (uint8_t*) malloc (linkMiu); + if (sConnlessRecvBuf == NULL) + { + ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu); + return NULL; + } + sConnlessRecvLen = linkMiu; + + // Create the write semaphore + if (sem_init (&sConnlessRecvSem, 0, 0) == -1) + { + ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return connectionlessCleanup (); + } + + sConnlessRecvWaitingForData = JNI_TRUE; + + // Wait for sConnlessRecvSem completion status + if (sem_wait (&sConnlessRecvSem)) + { + ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + // Create new LlcpPacket object + if (nfc_jni_cache_object (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1) + { + ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__); + return connectionlessCleanup (); + } + + // Get NativeConnectionless class object + clsLlcpPacket = e->GetObjectClass (llcpPacket); + if (e->ExceptionCheck ()) + { + e->ExceptionClear(); + ALOGE ("%s: Get Object class error", __FUNCTION__); + return connectionlessCleanup (); + } + + // Set Llcp Packet remote SAP + f = e->GetFieldID (clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField (llcpPacket, f, (jbyte) sConnlessRecvRemoteSap); + + // Set Llcp Packet Buffer + ALOGD ("%s: Received Llcp packet buffer size = %d\n", __FUNCTION__, sConnlessRecvLen); + f = e->GetFieldID (clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray (sConnlessRecvLen); + e->SetByteArrayRegion (receivedData, 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf); + e->SetObjectField (llcpPacket, f, receivedData); + +TheEnd: + connectionlessCleanup (); + if (sem_destroy (&sConnlessRecvSem)) + { + ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + return llcpPacket; +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_doClose +** +** Description: Close socket. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + jint handle = 0; + jclass c = NULL; + jfieldID f = NULL; + + ALOGD ("%s", __FUNCTION__); + + c = e->GetObjectClass (o); + f = e->GetFieldID (c, "mHandle", "I"); + handle = e->GetIntField (o, f); + + status = NFA_P2pDisconnect ((tNFA_HANDLE) handle, FALSE); + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status); + return JNI_FALSE; + } + return JNI_TRUE; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo}, + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom}, + {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeLlcpConnectionlessSocket +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e) +{ + return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods)); +} + + +} // android namespace diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..8b05b8e --- /dev/null +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NfcJniUtil.h" +#include "NfcAdaptation.h" +#include "PeerToPeer.h" +extern "C" +{ + #include "nfa_api.h" + #include "nfa_p2p_api.h" +} +extern tBRCM_JNI_HANDLE gNextJniHandle; + + +namespace android +{ + + +extern char* gNativeLlcpServiceSocketClassName; +extern char* gNativeLlcpSocketClassName; + + +/******************************************************************************* +** +** Function: nativeLlcpServiceSocket_doAccept +** +** Description: Accept a connection request from a peer. +** e: JVM environment. +** o: Java object. +** miu: Maximum information unit. +** rw: Receive window. +** linearBufferLength: Not used. +** +** Returns: LlcpSocket Java object. +** +*******************************************************************************/ +static jobject nativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + jclass clsNativeLlcpSocket = NULL; + jfieldID f = 0; + tBRCM_JNI_HANDLE serverHandle; //handle of the local server + bool stat = false; + tBRCM_JNI_HANDLE connHandle = gNextJniHandle++; + + ALOGD ("%s: enter", __FUNCTION__); + + serverHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e, o); + + stat = PeerToPeer::getInstance().accept (serverHandle, connHandle, miu, rw); + + if (! stat) + { + ALOGE ("%s: fail accept", __FUNCTION__); + goto TheEnd; + } + + /* Create new LlcpSocket object */ + if (nfc_jni_cache_object(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1) + { + ALOGE ("%s: fail create NativeLlcpSocket", __FUNCTION__); + goto TheEnd; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass (clientSocket); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: get class object error", __FUNCTION__); + goto TheEnd; + } + + /* Set socket handle */ + f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField (clientSocket, f, (jint) connHandle); + + /* Set socket MIU */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField (clientSocket, f, (jint)miu); + + /* Set socket RW */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField (clientSocket, f, (jint)rw); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return clientSocket; +} + + +/******************************************************************************* +** +** Function: nativeLlcpServiceSocket_doClose +** +** Description: Close a server socket. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + tBRCM_JNI_HANDLE jniServerHandle = 0; + bool stat = false; + + jniServerHandle = nfc_jni_get_nfc_socket_handle (e, o); + + stat = PeerToPeer::getInstance().deregisterServer (jniServerHandle); + + ALOGD ("%s: exit", __FUNCTION__); + return JNI_TRUE; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void*) nativeLlcpServiceSocket_doAccept}, + {"doClose", "()Z", (void*) nativeLlcpServiceSocket_doClose}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeLlcpServiceSocket +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv* e) +{ + return jniRegisterNativeMethods (e, gNativeLlcpServiceSocketClassName, + gMethods, NELEM(gMethods)); +} + + +} //namespace android + diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp new file mode 100644 index 0000000..cad6268 --- /dev/null +++ b/nci/jni/NativeLlcpSocket.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NfcJniUtil.h" +#include "PeerToPeer.h" + + +namespace android +{ + + +extern char* gNativeLlcpSocketClassName; + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doConnect +** +** Description: Establish a connection to the peer. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doConnect (JNIEnv* e, jobject o, jint nSap) +{ + bool stat = false; + jboolean retVal = JNI_FALSE; + + ALOGD ("%s: enter; sap=%d", __FUNCTION__, nSap); + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, nSap); + + if (stat) + retVal = JNI_TRUE; + + ALOGD ("%s: exit", __FUNCTION__); + return retVal; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doConnectBy +** +** Description: Establish a connection to the peer. +** e: JVM environment. +** o: Java object. +** sn: Service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + jboolean retVal = JNI_FALSE; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* + + stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, serviceName); + + e->ReleaseStringUTFChars (sn, serviceName); //free the string + + if (stat) + retVal = JNI_TRUE; + + ALOGD ("%s: exit", __FUNCTION__); + return retVal; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doClose +** +** Description: Close socket. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + jboolean retVal = JNI_FALSE; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().disconnectConnOriented (jniHandle); + + retVal = JNI_TRUE; + ALOGD ("%s: exit", __FUNCTION__); + return retVal; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doSend +** +** Description: Send data to peer. +** e: JVM environment. +** o: Java object. +** data: Buffer of data. +** +** Returns: True if sent ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data) +{ + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); + uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (data, NULL); + uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (data); + bool stat = false; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().send (jniHandle, dataBuffer, dataBufferLen); + + e->ReleaseByteArrayElements (data, (jbyte*) dataBuffer, JNI_ABORT); + + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__); + return stat ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doReceive +** +** Description: Receive data from peer. +** e: JVM environment. +** o: Java object. +** origBuffer: Buffer to put received data. +** +** Returns: Number of bytes received. +** +*******************************************************************************/ +static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuffer) +{ + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); + uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (origBuffer, NULL); + uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (origBuffer); + uint16_t actualLen = 0; + bool stat = false; + jint retval = 0; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().receive (jniHandle, dataBuffer, dataBufferLen, actualLen); + + if (stat && (actualLen>0)) + { + retval = actualLen; + } + else + retval = -1; + + e->ReleaseByteArrayElements (origBuffer, (jbyte*) dataBuffer, 0); + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doGetRemoteSocketMIU +** +** Description: Get peer's maximum information unit. +** e: JVM environment. +** o: Java object. +** +** Returns: Peer's maximum information unit. +** +*******************************************************************************/ +static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + jint miu = 0; + + miu = PeerToPeer::getInstance().getRemoteMaxInfoUnit (jniHandle); + + ALOGD ("%s: exit", __FUNCTION__); + return miu; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doGetRemoteSocketRW +** +** Description: Get peer's receive window size. +** e: JVM environment. +** o: Java object. +** +** Returns: Peer's receive window size. +** +*******************************************************************************/ +static jint nativeLlcpSocket_doGetRemoteSocketRW (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + jint rw = 0; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + rw = PeerToPeer::getInstance().getRemoteRecvWindow (jniHandle); + + ALOGD ("%s: exit", __FUNCTION__); + return rw; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", (void * ) nativeLlcpSocket_doConnect}, + {"doConnectBy", "(Ljava/lang/String;)Z", (void*) nativeLlcpSocket_doConnectBy}, + {"doClose", "()Z", (void *) nativeLlcpSocket_doClose}, + {"doSend", "([B)Z", (void *) nativeLlcpSocket_doSend}, + {"doReceive", "([B)I", (void *) nativeLlcpSocket_doReceive}, + {"doGetRemoteSocketMiu", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketMIU}, + {"doGetRemoteSocketRw", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeLlcpSocket +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeLlcpSocket (JNIEnv* e) +{ + return jniRegisterNativeMethods (e, gNativeLlcpSocketClassName, gMethods, NELEM(gMethods)); +} + + +} //namespace android + diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp new file mode 100755 index 0000000..0648852 --- /dev/null +++ b/nci/jni/NativeNfcManager.cpp @@ -0,0 +1,1686 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "NfcJniUtil.h" +#include "NfcAdaptation.h" +#include "SyncEvent.h" +#include "PeerToPeer.h" +#include "SecureElement.h" +#include "NfcTag.h" +#include "config.h" +#include "PowerSwitch.h" + +extern "C" +{ + #include "nfa_api.h" + #include "nfa_p2p_api.h" + #include "nfa_dta_api.h" + #include "rw_api.h" + #include "nfa_ee_api.h" + #include "nfa_brcm_api.h" + #include "nfa_cho_api.h" +} + +extern UINT8 *p_nfa_dm_lptd_cfg; +extern UINT8 *p_nfa_dm_start_up_cfg; +extern const UINT8 nfca_version_string []; +extern "C" void nfa_app_post_nci_reset (); +namespace android +{ + extern bool gIsTagDeactivating; + extern bool gIsSelectingRfInterface; + extern void nativeNfcTag_doTranseiveStatus (uint8_t * buf, uint32_t buflen); + extern void nativeNfcTag_doConnectStatus (jboolean is_connect_ok); + extern void nativeNfcTag_doDeactivateStatus (int status); + extern void nativeNfcTag_doWriteStatus (jboolean is_write_ok); + extern void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t max_size, uint32_t current_size, uint8_t flags); + extern void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status); + extern void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status); + extern void nativeNfcTag_formatStatus (bool is_ok); + extern void nativeNfcTag_resetPresenceCheck (); + extern void nativeNfcTag_doReadCompleted (tNFA_STATUS status); + extern void nativeNfcTag_abortWaits (); + extern void nativeLlcpConnectionlessSocket_abortWait (); + extern void nativeNfcTag_registerNdefTypeHandler (); + extern void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remote_sap); +} + + +/***************************************************************************** +** +** public variables and functions +** +*****************************************************************************/ +tBRCM_JNI_HANDLE gNextJniHandle = 1; +long gJniVersion = 411; + +namespace android +{ + int gGeneralTransceiveTimeout = 1000; + jmethodID gCachedNfcManagerNotifyNdefMessageListeners; + jmethodID gCachedNfcManagerNotifyTransactionListeners; + jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; + jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; + jmethodID gCachedNfcManagerNotifySeFieldActivated; + jmethodID gCachedNfcManagerNotifySeFieldDeactivated; + const char* gNativeP2pDeviceClassName = "com/android/nfc/dhimpl/NativeP2pDevice"; + const char* gNativeLlcpServiceSocketClassName = "com/android/nfc/dhimpl/NativeLlcpServiceSocket"; + const char* gNativeLlcpConnectionlessSocketClassName = "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket"; + const char* gNativeLlcpSocketClassName = "com/android/nfc/dhimpl/NativeLlcpSocket"; + const char* gNativeNfcTagClassName = "com/android/nfc/dhimpl/NativeNfcTag"; + const char* gNativeNfcManagerClassName = "com/android/nfc/dhimpl/NativeNfcManager"; + const char* gNativeNfcSecureElementClassName = "com/android/nfc/dhimpl/NativeNfcSecureElement"; + void doStartupConfig (); +} + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ +namespace android +{ +static jint sLastError = ERROR_BUFFER_TOO_SMALL; +static jmethodID sCachedNfcManagerNotifySeApduReceived; +static jmethodID sCachedNfcManagerNotifySeMifareAccess; +static jmethodID sCachedNfcManagerNotifySeEmvCardRemoval; +static jmethodID sCachedNfcManagerNotifyTargetDeselected; +static SyncEvent sNfaEnableEvent; //event for NFA_Enable() +static SyncEvent sNfaDisableEvent; //event for NFA_Disable() +static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling() +static SyncEvent sNfaSetConfigEvent; // event for Set_Config.... +static bool sIsNfaEnabled = false; +static bool sDiscoveryEnabled = false; //is polling for tag? +static bool sIsDisabling = false; +#define NFA_DM_PWR_STATE_UNKNOWN (-1) // power off sleep state is unkown until is is reported back from NFA... +static int sConnlessSap = 0; +static int sConnlessLinkMiu = 0; +static bool sAbortConnlessWait = false; +static bool sIsSecElemSelected = false; //has NFC service selected a sec elem +static UINT8 * sOriginalLptdCfg = NULL; +#define LPTD_PARAM_LEN (30) +static UINT8 sNewLptdCfg[LPTD_PARAM_LEN]; +static UINT32 sConfigUpdated = 0; +#define CONFIG_UPDATE_LPTD (1 << 0) +#define CONFIG_UPDATE_TECH_MASK (1 << 1) +#define DEFAULT_TECH_MASK (NFA_TECHNOLOGY_MASK_A \ + | NFA_TECHNOLOGY_MASK_B \ + | NFA_TECHNOLOGY_MASK_F \ + | NFA_TECHNOLOGY_MASK_ISO15693 \ + | NFA_TECHNOLOGY_MASK_B_PRIME \ + | NFA_TECHNOLOGY_MASK_A_ACTIVE \ + | NFA_TECHNOLOGY_MASK_F_ACTIVE) + + +static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); +static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); +static bool isPeerToPeer (tNFA_ACTIVATED& activated); +static void startRfDiscovery (bool isStart); +static void nfaBrcmInitCallback (UINT32 brcm_hw_id); + +///////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: getNative +** +** Description: Get native data +** +** Returns: Native data structure. +** +*******************************************************************************/ +nfc_jni_native_data *getNative (JNIEnv* e, jobject o) +{ + static struct nfc_jni_native_data *sCachedNat = NULL; + if (e) + { + sCachedNat = nfc_jni_get_nat(e, o); + } + return sCachedNat; +} + + +/******************************************************************************* +** +** Function: handleRfDiscoveryEvent +** +** Description: Handle RF-discovery events from the stack. +** discoveredDevice: Discovered device. +** +** Returns: None +** +*******************************************************************************/ +static void handleRfDiscoveryEvent (tNFC_RESULT_DEVT* discoveredDevice) +{ + if (discoveredDevice->more) + { + //there is more discovery notification coming + return; + } + + bool isP2p = NfcTag::getInstance ().isP2pDiscovered (); + if (isP2p) + { + //select the peer that supports P2P + NfcTag::getInstance ().selectP2p(); + } + else + { + //select the first of multiple tags that is discovered + NfcTag::getInstance ().selectFirstTag(); + } +} + + +/******************************************************************************* +** +** Function: nfaConnectionCallback +** +** Description: Receive connection-related events from stack. +** connEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventData) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + ALOGD("%s: event= %u", __FUNCTION__, connEvent); + + if (gIsTagDeactivating && connEvent != NFA_DEACTIVATED_EVT && connEvent != NFA_PRESENCE_CHECK_EVT && connEvent != NFA_DATA_EVT) + { + // special case to switching frame interface for ISO_DEP tags + gIsTagDeactivating = false; + ALOGD("%s: deactivating, should get NFA_DEACTIVATED_EVT", __FUNCTION__); + nativeNfcTag_doDeactivateStatus(1); + } + + switch (connEvent) + { + case NFA_POLL_ENABLED_EVT: // whether polling successfully started + { + ALOGD("%s: NFA_POLL_ENABLED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_POLL_DISABLED_EVT: // Listening/Polling stopped + { + ALOGD("%s: NFA_POLL_DISABLED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started + { + ALOGD("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event + { + ALOGD("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_DISC_RESULT_EVT: // NFC link/protocol discovery notificaiton + status = eventData->disc_result.status; + ALOGD("%s: NFA_DISC_RESULT_EVT: status = %d", __FUNCTION__, status); + if (status != NFA_STATUS_OK) + { + ALOGE("%s: NFA_DISC_RESULT_EVT error: status = %d", __FUNCTION__, status); + } + else + { + NfcTag::getInstance().connectionEventHandler(connEvent, eventData); + handleRfDiscoveryEvent(&eventData->disc_result.discovery_ntf); + } + break; + + case NFA_SELECT_RESULT_EVT: // NFC link/protocol discovery select response + ALOGD("%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = %d", __FUNCTION__, eventData->status, gIsSelectingRfInterface); + + if (eventData->status != NFA_STATUS_OK) + { + if (gIsSelectingRfInterface) + { + nativeNfcTag_doConnectStatus(false); + } + + ALOGE("%s: NFA_SELECT_RESULT_EVT error: status = %d", __FUNCTION__, eventData->status); + NFA_Deactivate (FALSE); + } + break; + + case NFA_DEACTIVATE_FAIL_EVT: + ALOGD("%s: NFA_DEACTIVATE_FAIL_EVT: status = %d", __FUNCTION__, eventData->status); + break; + + case NFA_ACTIVATED_EVT: // NFC link/protocol activated + ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d", __FUNCTION__, gIsSelectingRfInterface); + if (gIsSelectingRfInterface) + { + nativeNfcTag_doConnectStatus(true); + break; + } + + nativeNfcTag_resetPresenceCheck(); + if (isPeerToPeer(eventData->activated)) + { + ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); + break; + } + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + break; + + case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated + ALOGD("%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __FUNCTION__, eventData->deactivated.type,gIsTagDeactivating); + if (gIsTagDeactivating || gIsSelectingRfInterface) + { + if (gIsTagDeactivating) + nativeNfcTag_doDeactivateStatus(0); + break; + } + nativeNfcTag_resetPresenceCheck(); + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + break; + + case NFA_TLV_DETECT_EVT: // TLV Detection complete + status = eventData->tlv_detect.status; + ALOGD("%s: NFA_TLV_DETECT_EVT: status = %d, protocol = %d, num_tlvs = %d, num_bytes = %d", + __FUNCTION__, status, eventData->tlv_detect.protocol, + eventData->tlv_detect.num_tlvs, eventData->tlv_detect.num_bytes); + if (status != NFA_STATUS_OK) + { + ALOGE("%s: NFA_TLV_DETECT_EVT error: status = %d", __FUNCTION__, status); + } + break; + + case NFA_NDEF_DETECT_EVT: // NDEF Detection complete; + //if status is failure, it means the tag does not contain any or valid NDEF data; + //pass the failure status to the NFC Service; + status = eventData->ndef_detect.status; + ALOGD("%s: NFA_NDEF_DETECT_EVT: status = 0x%X, protocol = %u, " + "max_size = %lu, cur_size = %lu, flags = 0x%X", __FUNCTION__, + status, + eventData->ndef_detect.protocol, eventData->ndef_detect.max_size, + eventData->ndef_detect.cur_size, eventData->ndef_detect.flags); + nativeNfcTag_doCheckNdefResult(status, + eventData->ndef_detect.max_size, eventData->ndef_detect.cur_size, + eventData->ndef_detect.flags); + break; + + case NFA_DATA_EVT: // Data message received (for non-NDEF reads) + ALOGD("%s: NFA_DATA_EVT: len = %d", __FUNCTION__, eventData->data.len); + nativeNfcTag_doTranseiveStatus(eventData->data.p_data,eventData->data.len); + break; + + case NFA_SELECT_CPLT_EVT: // Select completed + status = eventData->status; + ALOGD("%s: NFA_SELECT_CPLT_EVT: status = %d", __FUNCTION__, status); + if (status != NFA_STATUS_OK) + { + ALOGE("%s: NFA_SELECT_CPLT_EVT error: status = %d", __FUNCTION__, status); + } + break; + + case NFA_READ_CPLT_EVT: // NDEF-read or tag-specific-read completed + ALOGD("%s: NFA_READ_CPLT_EVT: status = 0x%X", __FUNCTION__, eventData->status); + nativeNfcTag_doReadCompleted (eventData->status); + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + break; + + case NFA_WRITE_CPLT_EVT: // Write completed + ALOGD("%s: NFA_WRITE_CPLT_EVT: status = %d", __FUNCTION__, eventData->status); + nativeNfcTag_doWriteStatus (eventData->status == NFA_STATUS_OK); + break; + + case NFA_SET_TAG_RO_EVT: // Tag set as Read only + ALOGD("%s: NFA_SET_TAG_RO_EVT: status = %d", __FUNCTION__, eventData->status); + nativeNfcTag_doMakeReadonlyResult(eventData->status); + break; + + case NFA_CE_NDEF_WRITE_START_EVT: // NDEF write started + ALOGD("%s: NFA_CE_NDEF_WRITE_START_EVT: status: %d", __FUNCTION__, eventData->status); + + if (eventData->status != NFA_STATUS_OK) + ALOGE("%s: NFA_CE_NDEF_WRITE_START_EVT error: status = %d", __FUNCTION__, eventData->status); + break; + + case NFA_CE_NDEF_WRITE_CPLT_EVT: // NDEF write completed + ALOGD("%s: FA_CE_NDEF_WRITE_CPLT_EVT: len = %lu", __FUNCTION__, eventData->ndef_write_cplt.len); + break; + + case NFA_LLCP_ACTIVATED_EVT: // LLCP link is activated + ALOGD("%s: NFA_LLCP_ACTIVATED_EVT: is_initiator: %d remote_wks: %d, remote_lsc: %d, remote_link_miu: %d, local_link_miu: %d", + __FUNCTION__, + eventData->llcp_activated.is_initiator, + eventData->llcp_activated.remote_wks, + eventData->llcp_activated.remote_lsc, + eventData->llcp_activated.remote_link_miu, + eventData->llcp_activated.local_link_miu); + + PeerToPeer::getInstance().llcpActivatedHandler (getNative(0, 0), eventData->llcp_activated); + break; + + case NFA_LLCP_DEACTIVATED_EVT: // LLCP link is deactivated + ALOGD("%s: NFA_LLCP_DEACTIVATED_EVT", __FUNCTION__); + PeerToPeer::getInstance().llcpDeactivatedHandler (getNative(0, 0), eventData->llcp_deactivated); + break; + + case NFA_PRESENCE_CHECK_EVT: + ALOGD("%s: NFA_PRESENCE_CHECK_EVT", __FUNCTION__); + nativeNfcTag_doPresenceCheckResult (eventData->status); + break; + + case NFA_FORMAT_CPLT_EVT: + ALOGD("%s: NFA_FORMAT_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status); + nativeNfcTag_formatStatus (eventData->status == NFA_STATUS_OK); + break; + + case NFA_I93_CMD_CPLT_EVT: + ALOGD("%s: NFA_I93_CMD_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status); + break; + + case NFA_CE_UICC_LISTEN_CONFIGURED_EVT : + ALOGD("%s: NFA_CE_UICC_LISTEN_CONFIGURED_EVT : status=0x%X", __FUNCTION__, eventData->status); + SecureElement::getInstance().connectionEventHandler (connEvent, eventData); + break; + + case NFA_SET_P2P_LISTEN_TECH_EVT: + ALOGD("%s: NFA_SET_P2P_LISTEN_TECH_EVT", __FUNCTION__); + PeerToPeer::getInstance().connectionEventHandler (connEvent, eventData); + break; + + default: + ALOGE("%s: unknown event ????", __FUNCTION__); + break; + } +} + + +/******************************************************************************* +** +** Function: nfcManager_initNativeStruc +** +** Description: Initialize variables. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) +{ + nfc_jni_native_data* nat = NULL; + jclass cls = NULL; + jobject obj = NULL; + jfieldID f = 0; + + ALOGD ("%s: enter", __FUNCTION__); + + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if (nat == NULL) + { + ALOGE ("%s: fail allocate native data", __FUNCTION__); + return JNI_FALSE; + } + + memset (nat, 0, sizeof(*nat)); + e->GetJavaVM (&(nat->vm)); + nat->env_version = e->GetVersion (); + nat->manager = e->NewGlobalRef (o); + + cls = e->GetObjectClass (o); + f = e->GetFieldID (cls, "mNative", "I"); + e->SetIntField (o, f, (jint)nat); + + /* Initialize native cached references */ + gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID (cls, + "notifyNdefMessageListeners",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V" : "(Lcom/android/nfc/NativeNfcTag;)V"); + gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID (cls, + "notifyTransactionListeners", "([B)V"); + gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID (cls, + "notifyLlcpLinkActivation",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V" : "(Lcom/android/nfc/NativeP2pDevice;)V"); + gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID (cls, + "notifyLlcpLinkDeactivated",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V" : "(Lcom/android/nfc/NativeP2pDevice;)V"); + sCachedNfcManagerNotifyTargetDeselected = e->GetMethodID (cls, + "notifyTargetDeselected","()V"); + gCachedNfcManagerNotifySeFieldActivated = e->GetMethodID (cls, + "notifySeFieldActivated", "()V"); + gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID (cls, + "notifySeFieldDeactivated", "()V"); + + if (gJniVersion > 235) + { + sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + } + else + { + sCachedNfcManagerNotifySeApduReceived = NULL; + sCachedNfcManagerNotifySeMifareAccess = NULL; + sCachedNfcManagerNotifySeEmvCardRemoval = NULL; + } + + if (nfc_jni_cache_object(e,gNativeNfcTagClassName, &(nat->cached_NfcTag)) == -1) + { + ALOGE ("%s: fail cache NativeNfcTag", __FUNCTION__); + return JNI_FALSE; + } + + if (nfc_jni_cache_object(e,gNativeP2pDeviceClassName, &(nat->cached_P2pDevice)) == -1) + { + ALOGE ("%s: fail cache NativeP2pDevice", __FUNCTION__); + return JNI_FALSE; + } + + unsigned long num = 0; + + if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) + nat->tech_mask = num; + else + nat->tech_mask = DEFAULT_TECH_MASK; + + ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); + + // Always restore LPTD Configuration to the stack default. + if (sOriginalLptdCfg != NULL) + p_nfa_dm_lptd_cfg = sOriginalLptdCfg; + else + sOriginalLptdCfg = p_nfa_dm_lptd_cfg; + + // Override LPTD from the config file if it is found. + if (GetStrValue(NAME_LPTD_CFG, (char*)&sNewLptdCfg[0], sizeof(sNewLptdCfg))) + { + // Set stack pointer to use value. + p_nfa_dm_lptd_cfg = &sNewLptdCfg[0]; + } + + PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); + + ALOGD ("%s: exit", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfaDeviceManagementCallback +** +** Description: Receive device management events from stack. +** dmEvent: Device-management event ID. +** eventData: Data associated with event ID. +** +** Returns: None +** +*******************************************************************************/ +void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) +{ + ALOGD ("%s: enter; event=0x%X", __FUNCTION__, dmEvent); + + switch (dmEvent) + { + case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */ + { + SyncEventGuard guard (sNfaEnableEvent); + ALOGD ("%s: NFA_DM_ENABLE_EVT; status=0x%X", + __FUNCTION__, eventData->status); + sIsNfaEnabled = eventData->status == NFA_STATUS_OK; + sIsDisabling = false; + sNfaEnableEvent.notifyOne (); + } + break; + + case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */ + { + SyncEventGuard guard (sNfaDisableEvent); + ALOGD ("%s: NFA_DM_DISABLE_EVT", __FUNCTION__); + sIsNfaEnabled = false; + sIsDisabling = false; + sNfaDisableEvent.notifyOne (); + } + break; + + case NFA_DM_SET_CONFIG_EVT: //result of NFA_SetConfig + ALOGD ("%s: NFA_DM_SET_CONFIG_EVT", __FUNCTION__); + { + SyncEventGuard guard (sNfaSetConfigEvent); + sNfaSetConfigEvent.notifyOne(); + } + break; + + case NFA_DM_GET_CONFIG_EVT: /* Result of NFA_GetConfig */ + ALOGD ("%s: NFA_DM_GET_CONFIG_EVT", __FUNCTION__); + break; + + case NFA_DM_RF_FIELD_EVT: + ALOGD ("%s: NFA_DM_RF_FIELD_EVT; status=0x%X; field status=%u", __FUNCTION__, + eventData->rf_field.status, eventData->rf_field.rf_field_status); + + if (eventData->rf_field.status == NFA_STATUS_OK) + SecureElement::getInstance().notifyRfFieldEvent (eventData->rf_field.rf_field_status == NFA_DM_RF_FIELD_ON); + break; + + case NFA_DM_NFCC_TRANSPORT_ERR_EVT: + case NFA_DM_NFCC_TIMEOUT_EVT: + { + if (dmEvent == NFA_DM_NFCC_TIMEOUT_EVT) + ALOGD ("%s: NFA_DM_NFCC_TIMEOUT_EVT; abort all outstanding operations", __FUNCTION__); + else + ALOGD ("%s: NFA_DM_NFCC_TRANSPORT_ERR_EVT; abort all outstanding operations", __FUNCTION__); + + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + sAbortConnlessWait = true; + nativeLlcpConnectionlessSocket_abortWait(); + { + ALOGD ("%s: aborting sNfaEnableDisablePollingEvent", __FUNCTION__); + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne(); + } + { + ALOGD ("%s: aborting sNfaEnableEvent", __FUNCTION__); + SyncEventGuard guard (sNfaEnableEvent); + sNfaEnableEvent.notifyOne(); + } + { + ALOGD ("%s: aborting sNfaDisableEvent", __FUNCTION__); + SyncEventGuard guard (sNfaDisableEvent); + sNfaDisableEvent.notifyOne(); + } + sDiscoveryEnabled = false; + PowerSwitch::getInstance ().abort (); + + if (!sIsDisabling && sIsNfaEnabled) + { + NFA_Disable(FALSE); + sIsDisabling = true; + } + else + { + sIsNfaEnabled = false; + sIsDisabling = false; + } + PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL); + ALOGD ("%s: aborted all waiting events", __FUNCTION__); + } + break; + + case NFA_DM_PWR_MODE_CHANGE_EVT: + PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData); + break; + + default: + ALOGD ("%s: unhandled event", __FUNCTION__); + break; + } +} + + +/******************************************************************************* +** +** Function: nfcManager_doInitialize +** +** Description: Turn on NFC. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter; NCI_VERSION=0x%02X", __FUNCTION__, NCI_VERSION); + tNFA_STATUS stat = NFA_STATUS_OK; + + if (sIsNfaEnabled) + { + ALOGD ("%s: already enabled", __FUNCTION__); + goto TheEnd; + } + + { + unsigned long num = 0; + + NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); + theInstance.Initialize(); //start GKI, NCI task, NFC task + + SyncEventGuard guard (sNfaEnableEvent); + + NFA_Init(); + NFA_BrcmInit (nfaBrcmInitCallback); + + stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); + if (stat == NFA_STATUS_OK) + { + if (GetNumValue (NAME_APPL_TRACE_LEVEL, &num, sizeof (num))) + { + CE_SetTraceLevel (num); + LLCP_SetTraceLevel (num); + NFC_SetTraceLevel (num); + NCI_SetTraceLevel (num); + RW_SetTraceLevel (num); + NFA_SetTraceLevel (num); + NFA_ChoSetTraceLevel (num); + NFA_P2pSetTraceLevel (num); + NFA_SnepSetTraceLevel (num); + } + sNfaEnableEvent.wait(); //wait for NFA command to finish + + //sIsNfaEnabled indicates whether stack started successfully + if (sIsNfaEnabled) + { + SecureElement::getInstance().initialize (getNative(e, o)); + nativeNfcTag_registerNdefTypeHandler (); + NfcTag::getInstance().initialize (getNative(e, o)); + PeerToPeer::getInstance().initialize (gJniVersion); + PeerToPeer::getInstance().handleNfcOnOff (true); + + ///////////////////////////////////////////////////////////////////////////////// + // Add extra configuration here (work-arounds, etc.) + + // if this value is not set or set and non-zero, enable multi-technology responses. + if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) + NFA_SetMultiTechRsp(TRUE); + + // if this value is not set or set and non-zero, enable sleep mode. + if (!GetNumValue(NAME_NFA_DM_ENABLE_SLEEP, &num, sizeof(num)) || (num != 0)) + NFA_EnableSnoozeMode(); + + // Do custom NFCA startup configuration. + doStartupConfig(); + goto TheEnd; + } + } + + ALOGE ("%s: fail nfa enable; error=0x%X", __FUNCTION__, stat); + + if (sIsNfaEnabled) + stat = NFA_Disable (FALSE /* ungraceful */); + + theInstance.Finalize(); + } + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nfcManager_enableDiscovery +** +** Description: Start polling and listening for devices. +** e: JVM environment. +** o: Java object. +** mode: Not used. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) +{ + tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK; + struct nfc_jni_native_data *nat = getNative(e, o); + + if (nat) + tech_mask = (tNFA_TECHNOLOGY_MASK)nat->tech_mask; + + ALOGD ("%s: enter; tech_mask = %02x", __FUNCTION__, tech_mask); + + if (sDiscoveryEnabled) + { + ALOGE ("%s: already polling", __FUNCTION__); + return; + } + + tNFA_STATUS stat = NFA_STATUS_OK; + + ALOGD ("%s: sIsSecElemSelected=%u", __FUNCTION__, sIsSecElemSelected); + + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); + + { + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + stat = NFA_EnablePolling (tech_mask); + if (stat == NFA_STATUS_OK) + { + ALOGD ("%s: Waiting for sNfaEnableDisablePollingEvent", __FUNCTION__); + sDiscoveryEnabled = true; + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_START_EVT + ALOGD ("%s: Finished Waiting for sNfaEnableDisablePollingEvent", __FUNCTION__); + } + else + { + ALOGE ("%s: fail enable discovery; error=0x%X", __FUNCTION__, stat); + } + } + + // Start P2P listening if tag polling was enabled or the mask was 0. + if (sDiscoveryEnabled || (tech_mask == 0)) + { + ALOGD ("%s: Enable p2pListening", __FUNCTION__); + PeerToPeer::getInstance().enableP2pListening (true); + + //if NFC service has deselected the sec elem, then apply default routes + if (!sIsSecElemSelected) + stat = SecureElement::getInstance().routeToDefault (); + } + + // Actually start discovery. + startRfDiscovery (true); + + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: nfcManager_disableDiscovery +** +** Description: Stop polling and listening for devices. +** e: JVM environment. +** o: Java object. +** +** Returns: None +** +*******************************************************************************/ +void nfcManager_disableDiscovery (JNIEnv* e, jobject o) +{ + tNFA_STATUS status = NFA_STATUS_OK; + ALOGD ("%s: enter;", __FUNCTION__); + + if (sDiscoveryEnabled == false) + { + ALOGD ("%s: already disabled", __FUNCTION__); + goto TheEnd; + } + + // Stop RF Discovery. + startRfDiscovery (false); + + if (sDiscoveryEnabled) + { + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + status = NFA_DisablePolling (); + if (status == NFA_STATUS_OK) + { + sDiscoveryEnabled = false; + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_STOP_EVT + } + else + ALOGE ("%s: Failed to disable polling; error=0x%X", __FUNCTION__, status); + } + + PeerToPeer::getInstance().enableP2pListening (false); + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); +} + +/******************************************************************************* +** +** Function nfc_jni_cache_object_local +** +** Description Allocates a java object and calls it's constructor +** +** Returns -1 on failure, 0 on success +** +*******************************************************************************/ +int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cachedObj) +{ + jclass cls = NULL; + jobject obj = NULL; + jmethodID ctor = 0; + + cls = e->FindClass (className); + if(cls == NULL) + { + ALOGE ("%s: find class error", __FUNCTION__); + return -1; + } + + ctor = e->GetMethodID (cls, "", "()V"); + obj = e->NewObject (cls, ctor); + if (obj == NULL) + { + ALOGE ("%s: create object error", __FUNCTION__); + return -1; + } + + *cachedObj = e->NewLocalRef (obj); + if (*cachedObj == NULL) + { + e->DeleteLocalRef (obj); + ALOGE ("%s: global ref error", __FUNCTION__); + return -1; + } + e->DeleteLocalRef (obj); + return 0; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCreateLlcpServiceSocket +** +** Description: Create a new LLCP server socket. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** sn: Service name +** miu: Maximum information unit. +** rw: Receive window size. +** linearBufferLength: Max buffer size. +** +** Returns: NativeLlcpServiceSocket Java object. +** +*******************************************************************************/ +static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + bool stat = false; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket = NULL; + jfieldID f = 0; + tBRCM_JNI_HANDLE jniHandle = gNextJniHandle++; + const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* + std::string serviceName2 (serviceName); + + e->ReleaseStringUTFChars (sn, serviceName); //free the string + ALOGD ("%s: enter: sap=%i; name=%s; miu=%i; rw=%i; buffLen=%i", __FUNCTION__, nSap, serviceName2.c_str(), miu, rw, linearBufferLength); + + /* Create new NativeLlcpServiceSocket object */ + if (nfc_jni_cache_object(e, gNativeLlcpServiceSocketClassName, &(serviceSocket)) == -1) + { + ALOGE ("%s: Llcp socket object creation error", __FUNCTION__); + return NULL; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass (serviceSocket); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE("%s: Llcp Socket get object class error", __FUNCTION__); + return NULL; + } + + if (!PeerToPeer::getInstance().registerServer (jniHandle, serviceName2.c_str())) + { + ALOGE("%s: RegisterServer error", __FUNCTION__); + return NULL; + } + + /* Set socket handle to be the same as the NfaHandle*/ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField (serviceSocket, f, (jint) jniHandle); + ALOGD ("%s: socket Handle = 0x%X", __FUNCTION__, jniHandle); + + /* Set socket linear buffer length */ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField (serviceSocket, f,(jint)linearBufferLength); + ALOGD ("%s: buffer length = %d", __FUNCTION__, linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField (serviceSocket, f,(jint)miu); + ALOGD ("%s: MIU = %d", __FUNCTION__, miu); + + /* Set socket RW */ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField (serviceSocket, f,(jint)rw); + ALOGD ("%s: RW = %d", __FUNCTION__, rw); + + sLastError = 0; + ALOGD ("%s: exit", __FUNCTION__); + return serviceSocket; +} + + +/******************************************************************************* +** +** Function: nfcManager_doGetLastError +** +** Description: Get the last error code. +** e: JVM environment. +** o: Java object. +** +** Returns: Last error code. +** +*******************************************************************************/ +static jint nfcManager_doGetLastError(JNIEnv* e, jobject o) +{ + ALOGD ("%s: last error=%i", __FUNCTION__, sLastError); + return sLastError; +} + + +/******************************************************************************* +** +** Function: nfcManager_doDeinitialize +** +** Description: Turn off NFC. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nfcManager_doDeinitialize (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + + sIsDisabling = true; + + SecureElement::getInstance().finalize (); + + if (sIsNfaEnabled) + { + SyncEventGuard guard (sNfaDisableEvent); + tNFA_STATUS stat = NFA_Disable (TRUE /* graceful */); + if (stat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for completion", __FUNCTION__); + sNfaDisableEvent.wait (); //wait for NFA command to finish + PeerToPeer::getInstance ().handleNfcOnOff (false); + } + else + { + ALOGE ("%s: fail disable; error=0x%X", __FUNCTION__, stat); + } + } + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + sAbortConnlessWait = true; + nativeLlcpConnectionlessSocket_abortWait(); + sIsNfaEnabled = false; + sDiscoveryEnabled = false; + sIsDisabling = false; + sIsSecElemSelected = false; + + { + //unblock NFA_EnablePolling() and NFA_DisablePolling() + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + + NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); + theInstance.Finalize(); + + ALOGD ("%s: exit", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCreateLlcpSocket +** +** Description: Create a LLCP connection-oriented socket. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** miu: Maximum information unit. +** rw: Receive window size. +** linearBufferLength: Max buffer size. +** +** Returns: NativeLlcpSocket Java object. +** +*******************************************************************************/ +static jobject nfcManager_doCreateLlcpSocket (JNIEnv* e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + ALOGD ("%s: enter; sap=%d; miu=%d; rw=%d; buffer len=%d", __FUNCTION__, nSap, miu, rw, linearBufferLength); + jobject clientSocket = NULL; + jclass clsNativeLlcpSocket; + jfieldID f; + tBRCM_JNI_HANDLE jniHandle = gNextJniHandle++; + bool stat = false; + + stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw); + + /* Create new NativeLlcpSocket object */ + if (nfc_jni_cache_object_local(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1) + { + ALOGE ("%s: fail Llcp socket creation", __FUNCTION__); + goto TheEnd; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass (clientSocket); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail get class object", __FUNCTION__); + goto TheEnd; + } + + /* Set socket SAP */ + f = e->GetFieldID (clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField (clientSocket, f, (jint) nSap); + + /* Set socket handle */ + f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField (clientSocket, f, (jint) jniHandle); + + /* Set socket MIU */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField (clientSocket, f, (jint) miu); + + /* Set socket RW */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField (clientSocket, f, (jint) rw); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return clientSocket; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCreateLlcpConnectionlessSocket +** +** Description: Create a connection-less socket. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** sn: Service name. +** +** Returns: NativeLlcpConnectionlessSocket Java object. +** +*******************************************************************************/ +static jobject nfcManager_doCreateLlcpConnectionlessSocket (JNIEnv *e, jobject o, jint nSap, jstring sn) +{ + ALOGD ("%s: nSap=0x%X", __FUNCTION__, nSap); + return NULL; +} + + +/******************************************************************************* +** +** Function: nfcManager_doGetSecureElementList +** +** Description: Get a list of secure element handles. +** e: JVM environment. +** o: Java object. +** +** Returns: List of secure element handles. +** +*******************************************************************************/ +static jintArray nfcManager_doGetSecureElementList(JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return SecureElement::getInstance().getListOfEeHandles (e); +} + + +/******************************************************************************* +** +** Function: nfcManager_doSelectSecureElement +** +** Description: NFC controller starts routing data in listen mode. +** e: JVM environment. +** o: Java object. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = true; + + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); + + // Stop RF Discovery. + startRfDiscovery (false); + + if (sIsSecElemSelected) + { + ALOGD ("%s: already selected", __FUNCTION__); + goto TheEnd; + } + + stat = SecureElement::getInstance().activate (0xABCDEF); + if (stat) + SecureElement::getInstance().routeToSecureElement (); + sIsSecElemSelected = true; + +TheEnd: + // Restart RF Discovery. + startRfDiscovery (true); + + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: nfcManager_doDeselectSecureElement +** +** Description: NFC controller stops routing data in listen mode. +** e: JVM environment. +** o: Java object. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + bool isPowerLevelChanged = false; + + if (! sIsSecElemSelected) + { + ALOGE ("%s: already deselected", __FUNCTION__); + goto TheEnd; + } + + if (PowerSwitch::getInstance ().getLevel() == PowerSwitch::LOW_POWER) + { + ALOGD ("%s: do not deselect while power is OFF", __FUNCTION__); + sIsSecElemSelected = false; + goto TheEnd; + } + + stat = SecureElement::getInstance().routeToDefault (); + sIsSecElemSelected = false; + + //if controller is not routing to sec elems AND there is no pipe connected, + //then turn off the sec elems + if (SecureElement::getInstance().isBusy() == false) + SecureElement::getInstance().deactivate (0xABCDEF); + +TheEnd: + //if power level was changed at the top of this method, + //then restore to low power + if (isPowerLevelChanged || (!PowerSwitch::getInstance().isScreenOn() && (sDiscoveryEnabled == false)) ) + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: isPeerToPeer +** +** Description: Whether the activation data indicates the peer supports NFC-DEP. +** activated: Activation data. +** +** Returns: True if the peer supports NFC-DEP. +** +*******************************************************************************/ +static bool isPeerToPeer (tNFA_ACTIVATED& activated) +{ + return activated.activate_ntf.protocol == NFA_PROTOCOL_NFC_DEP; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCheckLlcp +** +** Description: Not used. +** +** Returns: True +** +*******************************************************************************/ +static jboolean nfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doActivateLlcp +** +** Description: Not used. +** +** Returns: True +** +*******************************************************************************/ +static jboolean nfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doAbort +** +** Description: Not used. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doAbort(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: nfcManager_doDownload +** +** Description: Not used. +** +** Returns: True +** +*******************************************************************************/ +static jboolean nfcManager_doDownload(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doResetTimeouts +** +** Description: Not used. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o) +{ + ALOGD ("%s: %d millisec", __FUNCTION__, DEFAULT_GENERAL_TRANS_TIMEOUT); + gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT; +} + + +/******************************************************************************* +** +** Function: nfcManager_doSetTimeout +** +** Description: Set timeout value. +** e: JVM environment. +** o: Java object. +** timeout: Timeout value. +** +** Returns: True if ok. +** +*******************************************************************************/ +static bool nfcManager_doSetTimeout(JNIEnv *e, jobject o, jint tech, jint timeout) +{ + if (timeout <= 0) + { + ALOGE("%s: Timeout must be positive.",__FUNCTION__); + return false; + } + + ALOGD ("%s: timeout=%d", __FUNCTION__, timeout); + gGeneralTransceiveTimeout = timeout; + return true; +} + + +/******************************************************************************* +** +** Function: nfcManager_doGetTimeout +** +** Description: Get timeout value. +** e: JVM environment. +** o: Java object. +** tech: Not used. +** +** Returns: Timeout value. +** +*******************************************************************************/ +static jint nfcManager_doGetTimeout(JNIEnv *e, jobject o, jint tech) +{ + ALOGD ("%s: timeout=%d", __FUNCTION__, gGeneralTransceiveTimeout); + return gGeneralTransceiveTimeout; +} + + +/******************************************************************************* +** +** Function: nfcManager_doDump +** +** Description: Not used. +** e: JVM environment. +** o: Java object. +** +** Returns: Text dump. +** +*******************************************************************************/ +static jstring nfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", /*libnfc_llc_error_count*/ 0); + return e->NewStringUTF(buffer); +} + + +/******************************************************************************* +** +** Function: nfcManager_doSetP2pInitiatorModes +** +** Description: Set P2P initiator's activation modes. +** e: JVM environment. +** o: Java object. +** modes: Active and/or passive modes. The values are specified +** in external/libnfc-nxp/inc/phNfcTypes.h. See +** enum phNfc_eP2PMode_t. +** +** Returns: None. +** +*******************************************************************************/ +static void nfcManager_doSetP2pInitiatorModes (JNIEnv *e, jobject o, jint modes) +{ + ALOGD ("%s: modes=0x%X", __FUNCTION__, modes); + //this function is not called by the NFC service nor exposed by public API. +} + + +/******************************************************************************* +** +** Function: nfcManager_doSetP2pTargetModes +** +** Description: Set P2P target's activation modes. +** e: JVM environment. +** o: Java object. +** modes: Active and/or passive modes. +** +** Returns: None. +** +*******************************************************************************/ +static void nfcManager_doSetP2pTargetModes (JNIEnv *e, jobject o, jint modes) +{ + ALOGD ("%s: modes=0x%X", __FUNCTION__, modes); + //this function is not called by the NFC service nor exposed by public API. +} + +/******************************************************************************* +** +** Function nfcManager_doSetScreenState +** +** Description Forward the Screen On/Off state to native code for enhanced +** power saving mode. +** +** Returns true +** +*******************************************************************************/ +jboolean nfcManager_doSetScreenState(JNIEnv *e, jobject o, jboolean screenState) +{ + ALOGD ("%s(%d)", __FUNCTION__, screenState); + PowerSwitch::getInstance().setScreenState(screenState == JNI_TRUE); + return JNI_TRUE; +} + +/***************************************************************************** +** +** JNI functions for android-4.0.1_r1 +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)nfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void*) nfcManager_initNativeStruc}, + + {"doInitialize", "()Z", + (void*) nfcManager_doInitialize}, + + {"doDeinitialize", "()Z", + (void*) nfcManager_doDeinitialize}, + + {"enableDiscovery", "()V", + (void*) nfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)nfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)nfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)nfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)nfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)nfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;", + (void *)nfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;", + (void*) nfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", + (void*) nfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void*) nfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void*) nfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)nfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)nfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)nfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)nfcManager_doAbort}, + + {"doSetP2pInitiatorModes", "(I)V", + (void *)nfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes", "(I)V", + (void *)nfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)nfcManager_doDump}, + + {"doSetScreenState", "(Z)Z", + (void *)nfcManager_doSetScreenState}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeNfcManager +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeNfcManager (JNIEnv *e) +{ + GetNumValue (NAME_JNI_VERSION, &gJniVersion, sizeof(gJniVersion)); + ALOGD ("%s: enter, %s=%lu", __FUNCTION__, NAME_JNI_VERSION, gJniVersion); + PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL); + ALOGD ("%s: exit", __FUNCTION__); + return jniRegisterNativeMethods (e, gNativeNfcManagerClassName, gMethods, NELEM (gMethods)); +} + + +/******************************************************************************* +** +** Function: startRfDiscovery +** +** Description: Ask stack to start polling and listening for devices. +** isStart: Whether to start. +** +** Returns: None +** +*******************************************************************************/ +void startRfDiscovery(bool isStart) +{ + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + tNFA_STATUS status = NFA_STATUS_FAILED; + + ALOGD ("%s: is start=%d", __FUNCTION__, isStart); + + status = isStart ? NFA_StartRfDiscovery () : NFA_StopRfDiscovery (); + if (status == NFA_STATUS_OK) + { + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_RF_DISCOVERY_xxxx_EVT + } + else + { + ALOGE ("%s: Failed to start/stop RF discovery; error=0x%X", __FUNCTION__, status); + } +} + + +/******************************************************************************* +** +** Function: doStartupConfig +** +** Description: Configure the NFC controller. +** +** Returns: None +** +*******************************************************************************/ +void doStartupConfig() +{ + unsigned long num = 0; + struct nfc_jni_native_data *nat = getNative(0, 0); + + // Enable the "RC workaround" to allow our stack/firmware to work with a retail + // Nexus S that causes IOP issues. Only enable if value exists and set to 1. + if (GetNumValue(NAME_USE_NXP_P2P_RC_WORKAROUND, &num, sizeof(num)) && (num == 1)) + { +#if (NCI_VERSION > NCI_VERSION_20791B0) + UINT8 nfa_dm_rc_workaround[] = { 0x03, 0x0f, 0xab }; +#else + UINT8 nfa_dm_rc_workaround[] = { 0x01, 0x0f, 0xab, 0x01 }; +#endif + + ALOGD ("%s: Configure RC work-around", __FUNCTION__); + NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]); + } + + // If polling for Active mode, set the ordering so that we choose Active over Passive mode first. + if (nat && (nat->tech_mask & (NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE))) + { + UINT8 act_mode_order_param[] = { 0x01 }; + NFA_SetConfig(NCI_PARAM_ID_ACT_ORDER, sizeof(act_mode_order_param), &act_mode_order_param[0]); + } + + // Set configuration to allow UICC to Power off if there is no traffic. + if (GetNumValue(NAME_UICC_IDLE_TIMEOUT, &num, sizeof(num)) && (num != 0)) + { + // 61 => The least significant bit of this byte enables the power off when Idle mode. + // 00 87 93 03 == > These 4 bytes form a 4 byte value which decides the idle timeout(in us) + // value to trigger the uicc deactivation. + // e.g. in current example its value is 0x3938700 i.e. 60000000 is 60 seconds. + UINT8 swpcfg_param[] = { 0x61, 0x00, 0x82, 0x04, 0x20, 0xA1, 0x07, 0x00, + 0x90, 0xD0, 0x03, 0x00, 0x00, 0x87, 0x93, 0x03 }; + + ALOGD ("%s: Configure UICC idle-timeout to %lu ms", __FUNCTION__, num); + + // Set the timeout from the .conf file value. + num *= 1000; + UINT8 * p = &swpcfg_param[12]; + UINT32_TO_STREAM(p, num) + + NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]); + } + + // Set antenna tuning configuration if configured. +#define PREINIT_DSP_CFG_SIZE 30 + UINT8 preinit_dsp_param[PREINIT_DSP_CFG_SIZE]; + + if (GetStrValue(NAME_PREINIT_DSP_CFG, (char*)&preinit_dsp_param[0], sizeof(preinit_dsp_param))) + { + NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_param[0]); + } +} + + +/******************************************************************************* +** +** Function: nfcManager_isNfcActive +** +** Description: Used externaly to determine if NFC is active or not. +** +** Returns: 'true' if the NFC stack is running, else 'false'. +** +*******************************************************************************/ +bool nfcManager_isNfcActive() +{ + return sIsNfaEnabled; +} + + +/******************************************************************************* +** +** Function: nfaBrcmInitCallback +** +** Description: Callback function for application to start device initialization. +** When platform-specific initialization is completed, +** NCI_BrcmDevInitDone() must be called to proceed with stack start up. +** +** Returns: None. +** +*******************************************************************************/ +void nfaBrcmInitCallback (UINT32 brcm_hw_id) +{ + nfa_app_post_nci_reset (); +} + + +} /* namespace android */ + diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp new file mode 100755 index 0000000..7a92b44 --- /dev/null +++ b/nci/jni/NativeNfcTag.cpp @@ -0,0 +1,1554 @@ +/* + * Copyright (C) 2011 Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "NfcJniUtil.h" +#include "NfcTag.h" +#include "config.h" +#include "Mutex.h" +#include "IntervalTimer.h" + +extern "C" +{ + #include "nfa_api.h" + #include "nfa_rw_api.h" + #include "ndef_utils.h" + #include "rw_api.h" +} +namespace android +{ + extern nfc_jni_native_data* getNative(JNIEnv *e, jobject o); + extern char* gNativeNfcTagClassName; + extern bool nfcManager_isNfcActive(); + extern int gGeneralTransceiveTimeout; +} +extern long gJniVersion; + + +/***************************************************************************** +** +** public variables and functions +** +*****************************************************************************/ +namespace android +{ + bool gIsTagDeactivating = false; // flag for nfa callback indicating we are deactivating for RF interface switch + bool gIsSelectingRfInterface = false; // flag for nfa callback indicating we are selecting for RF interface switch +} + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ +namespace android +{ + + +// Pre-defined tag type values. These must match the values in +// framework Ndef.java for Google public NFC API. +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 + +#define STATUS_CODE_TARGET_LOST 146 // this error code comes from the service + +static uint32_t sCheckNdefCurrentSize = 0; +static tNFA_STATUS sCheckNdefStatus = 0; //whether tag already contains a NDEF message +static bool sCheckNdefCapable = false; //whether tag has NDEF capability +static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; +static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP; +static uint8_t* sTransceiveData = NULL; +static uint32_t sTransceiveDataLen = 0; +static bool sWaitingForTransceive = false; +static bool sNeedToSwitchRf = false; +static Mutex sRfInterfaceMutex; +static uint32_t sReadDataLen = 0; +static uint8_t* sReadData = NULL; +static bool sIsReadingNdefMessage = false; +static SyncEvent sReadEvent; +static sem_t sWriteSem; +static sem_t sFormatSem; +static SyncEvent sTransceiveEvent; +static SyncEvent sReconnectEvent; +static sem_t sCheckNdefSem; +static sem_t sPresenceCheckSem; +static sem_t sMakeReadonlySem; +static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back to ISO_DEP frame interface +static jboolean sWriteOk = JNI_FALSE; +static jboolean sWriteWaitingForComplete = JNI_FALSE; +static bool sFormatOk = false; +static jboolean sConnectOk = JNI_FALSE; +static jboolean sConnectWaitingForComplete = JNI_FALSE; +static bool sGotDeactivate = false; +static uint32_t sCheckNdefMaxSize = 0; +static bool sCheckNdefCardReadOnly = false; +static jboolean sCheckNdefWaitingForComplete = JNI_FALSE; +static int sCountTagAway = 0; //count the consecutive number of presence-check failures +static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED; +static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE; + +static int reSelect (tNFA_INTF_TYPE rfInterface); +static bool switchRfInterface(tNFA_INTF_TYPE rfInterface); + + +/******************************************************************************* +** +** Function: nativeNfcTag_abortWaits +** +** Description: Unblock all thread synchronization objects. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_abortWaits () +{ + ALOGD ("%s", __FUNCTION__); + { + SyncEventGuard g (sReadEvent); + sReadEvent.notifyOne (); + } + sem_post (&sWriteSem); + sem_post (&sFormatSem); + { + SyncEventGuard g (sTransceiveEvent); + sTransceiveEvent.notifyOne (); + } + { + SyncEventGuard g (sReconnectEvent); + sReconnectEvent.notifyOne (); + } + + sem_post (&sCheckNdefSem); + sem_post (&sPresenceCheckSem); + sem_post (&sMakeReadonlySem); +} + + +/******************************************************************************* +** +** Function: switchBackTimerProc +** +** Description: Callback function for interval timer. +** +** Returns: None +** +*******************************************************************************/ +static void switchBackTimerProc (union sigval) +{ + ALOGD ("%s", __FUNCTION__); + switchRfInterface(NFA_INTERFACE_ISO_DEP); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doReadCompleted +** +** Description: Receive the completion status of read operation. Called by +** NFA_READ_CPLT_EVT. +** status: Status of operation. +** +** Returns: None +** +*******************************************************************************/ +//called by NFA_READ_CPLT_EVT when NDEF message has been completely read +void nativeNfcTag_doReadCompleted (tNFA_STATUS status) +{ + ALOGD ("%s: status=0x%X; is reading=%u", __FUNCTION__, status, sIsReadingNdefMessage); + + if (sIsReadingNdefMessage == false) + return; //not reading NDEF message right now, so just return + + if (status != NFA_STATUS_OK) + { + sReadDataLen = 0; + if (sReadData) + free (sReadData); + sReadData = NULL; + } + SyncEventGuard g (sReadEvent); + sReadEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: ndefHandlerCallback +** +** Description: Receive NDEF-message related events from stack. +** event: Event code. +** p_data: Event data. +** +** Returns: None +** +*******************************************************************************/ +static void ndefHandlerCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *eventData) +{ + ALOGD ("%s: event=%u, eventData=%p", __FUNCTION__, event, eventData); + + switch (event) + { + case NFA_NDEF_REGISTER_EVT: + { + tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg; + ALOGD ("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X", __FUNCTION__, ndef_reg.status, ndef_reg.ndef_type_handle); + sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle; + } + break; + + case NFA_NDEF_DATA_EVT: + { + ALOGD ("%s: NFA_NDEF_DATA_EVT; data_len = %lu", __FUNCTION__, eventData->ndef_data.len); + sReadDataLen = eventData->ndef_data.len; + sReadData = (uint8_t*) malloc (sReadDataLen); + memcpy (sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len); + } + break; + + default: + ALOGE ("%s: Unknown event %u ????", __FUNCTION__, event); + break; + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doRead +** +** Description: Read the NDEF message on the tag. +** e: JVM environment. +** o: Java object. +** +** Returns: NDEF message. +** +*******************************************************************************/ +static jbyteArray nativeNfcTag_doRead (JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + tNFA_STATUS status = NFA_STATUS_FAILED; + jbyteArray buf = NULL; + + sReadDataLen = 0; + if (sReadData != NULL) + { + free (sReadData); + sReadData = NULL; + } + + if (sCheckNdefCurrentSize > 0) + { + SyncEventGuard g (sReadEvent); + sIsReadingNdefMessage = true; + status = NFA_RwReadNDef (); + sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT + sIsReadingNdefMessage = false; + + if (sReadDataLen > 0) //if stack actually read data from the tag + { + ALOGD ("%s: read %u bytes", __FUNCTION__, sReadDataLen); + buf = e->NewByteArray (sReadDataLen); + e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData); + } + } + else + { + ALOGD ("%s: create emtpy buffer", __FUNCTION__); + static uint8_t* empty = (uint8_t*) ""; + sReadDataLen = 0; + sReadData = (uint8_t*) malloc (1); + buf = e->NewByteArray (sReadDataLen); + e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData); + } + + if (sReadData) + { + free (sReadData); + sReadData = NULL; + } + sReadDataLen = 0; + + ALOGD ("%s: exit", __FUNCTION__); + return buf; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doWriteStatus +** +** Description: Receive the completion status of write operation. Called +** by NFA_WRITE_CPLT_EVT. +** isWriteOk: Status of operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doWriteStatus (jboolean isWriteOk) +{ + if (sWriteWaitingForComplete != JNI_FALSE) + { + sWriteWaitingForComplete = JNI_FALSE; + sWriteOk = isWriteOk; + sem_post (&sWriteSem); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_formatStatus +** +** Description: Receive the completion status of format operation. Called +** by NFA_FORMAT_CPLT_EVT. +** isOk: Status of operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_formatStatus (bool isOk) +{ + sFormatOk = isOk; + sem_post (&sFormatSem); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doWrite +** +** Description: Write a NDEF message to the tag. +** e: JVM environment. +** o: Java object. +** buf: Contains a NDEF message. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doWrite (JNIEnv *e, jobject o, jbyteArray buf) +{ + jboolean result = JNI_FALSE; + tNFA_STATUS status = 0; + UINT32 len = 0; + UINT8* p_data = NULL; + const int maxBufferSize = 1024; + UINT8 buffer[maxBufferSize] = { 0 }; + UINT32 curDataSize = 0; + + len = (UINT32) e->GetArrayLength (buf); + p_data = (UINT8*) e->GetByteArrayElements (buf, NULL); + + ALOGD ("%s: enter; len = %lu", __FUNCTION__, len); + + /* Create the write semaphore */ + if (sem_init (&sWriteSem, 0, 0) == -1) + { + ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + sWriteWaitingForComplete = JNI_TRUE; + if (sCheckNdefStatus == NFA_STATUS_FAILED) + { + //if tag does not contain a NDEF message + //and tag is capable of storing NDEF message + if (sCheckNdefCapable) + { + ALOGD ("%s: try format", __FUNCTION__); + sem_init (&sFormatSem, 0, 0); + sFormatOk = false; + status = NFA_RwFormatTag (); + sem_wait (&sFormatSem); + sem_destroy (&sFormatSem); + if (sFormatOk == false) //if format operation failed + goto TheEnd; + } + ALOGD ("%s: try write", __FUNCTION__); + status = NFA_RwWriteNDef (p_data, len); + } + else if (len == 0) + { + //if (NXP TagWriter wants to erase tag) then create and write an empty ndef message + NDEF_MsgInit (buffer, maxBufferSize, &curDataSize); + status = NDEF_MsgAddRec (buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY, NULL, 0, NULL, 0, NULL, 0); + ALOGD ("%s: create empty ndef msg; status=%u; size=%lu", __FUNCTION__, status, curDataSize); + status = NFA_RwWriteNDef (buffer, curDataSize); + } + else + { + ALOGD ("%s: NFA_RwWriteNDef", __FUNCTION__); + status = NFA_RwWriteNDef (p_data, len); + } + + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: write/format error=%d", __FUNCTION__, status); + goto TheEnd; + } + + /* Wait for write completion status */ + sWriteOk = false; + if (sem_wait (&sWriteSem)) + { + ALOGE ("%s: wait semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + result = sWriteOk; + +TheEnd: + /* Destroy semaphore */ + if (sem_destroy (&sWriteSem)) + { + ALOGE ("%s: failed destroy semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + sWriteWaitingForComplete = JNI_FALSE; + ALOGD ("%s: exit; result=%d", __FUNCTION__, result); + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doConnectStatus +** +** Description: Receive the completion status of connect operation. +** isConnectOk: Status of the operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doConnectStatus (jboolean isConnectOk) +{ + if (sConnectWaitingForComplete != JNI_FALSE) + { + sConnectWaitingForComplete = JNI_FALSE; + sConnectOk = isConnectOk; + SyncEventGuard g (sReconnectEvent); + sReconnectEvent.notifyOne (); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doDeactivateStatus +** +** Description: Receive the completion status of deactivate operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doDeactivateStatus (int status) +{ + sGotDeactivate = (status == 0); + + SyncEventGuard g (sReconnectEvent); + sReconnectEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doConnect +** +** Description: Connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: Must return NXP status code, which NFC service expects. +** +*******************************************************************************/ +static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle) +{ + ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); + int i = targetHandle; + struct nfc_jni_native_data *nat = getNative (0, 0); + NfcTag& natTag = NfcTag::getInstance (); + sNeedToSwitchRf = false; + + if (i >= NfcTag::MAX_NUM_TECHNOLOGY) + { + ALOGE ("%s: Handle not found", __FUNCTION__); + return NFCSTATUS_FAILED; + } + + if (natTag.mTechLibNfcTypes[i] != NFC_PROTOCOL_ISO_DEP) + { + ALOGD ("%s() Nfc type = %d, do nothing for non ISO_DEP", __FUNCTION__, natTag.mTechLibNfcTypes[i]); + return NFCSTATUS_SUCCESS; + } + + if (natTag.mTechList[i] == TARGET_TYPE_ISO14443_3A || natTag.mTechList[i] == TARGET_TYPE_ISO14443_3B) + { + ALOGD ("%s: switching to tech: %d need to switch rf intf to frame", __FUNCTION__, natTag.mTechList[i]); + // connecting to NfcA or NfcB don't actually switch until/unless we get a transceive + sNeedToSwitchRf = true; + } + else + { + // connecting back to IsoDep or NDEF + return (switchRfInterface (NFA_INTERFACE_ISO_DEP) ? NFCSTATUS_SUCCESS : NFCSTATUS_FAILED); + } + + return NFCSTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function: reSelect +** +** Description: Deactivates the tag and re-selects it with the specified +** rf interface. +** +** Returns: status code, 0 on success, 1 on failure, +** 146 (defined in service) on tag lost +** +*******************************************************************************/ +static int reSelect (tNFA_INTF_TYPE rfInterface) +{ + ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface); + NfcTag& natTag = NfcTag::getInstance (); + + ALOGD ("%s: NFA_Deactivate()", __FUNCTION__); + tNFA_STATUS status; + int rVal = 1; + + do + { + SyncEventGuard g (sReconnectEvent); + gIsTagDeactivating = true; + sGotDeactivate = false; + if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) + { + ALOGE ("%s: NFA_Deactivate failed, status = %d", __FUNCTION__, status); + break; + } + + if (sReconnectEvent.wait (1000) == false) //if timeout occured + { + ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__); + } + + if (! NfcTag::getInstance ().isActivated ()) + { + rVal = STATUS_CODE_TARGET_LOST; + break; + } + + gIsTagDeactivating = false; + + SyncEventGuard g2 (sReconnectEvent); + + sConnectWaitingForComplete = JNI_TRUE; + ALOGD ("%s: NFA_Select()", __FUNCTION__); + gIsSelectingRfInterface = true; + if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface))) + { + ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status); + break; + } + + sConnectOk = false; + if (sReconnectEvent.wait (1000) == false) //if timeout occured + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + break; + } + ALOGD("%s: done waiting on NFA_Select() sConnectOk=%d", __FUNCTION__, sConnectOk); + if (! NfcTag::getInstance ().isActivated ()) + { + ALOGD("%s: Tag no longer active", __FUNCTION__); + rVal = STATUS_CODE_TARGET_LOST; + break; + } + rVal = (sConnectOk) ? 0 : 1; + } while (0); + + sConnectWaitingForComplete = JNI_FALSE; + gIsTagDeactivating = false; + gIsSelectingRfInterface = false; + return rVal; +} + +/******************************************************************************* +** +** Function: switchRfInterface +** +** Description: Switch controller's RF interface to frame, ISO-DEP, or NFC-DEP. +** rfInterface: Type of RF interface. +** +** Returns: True if ok. +** +*******************************************************************************/ +static bool switchRfInterface (tNFA_INTF_TYPE rfInterface) +{ + ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface); + NfcTag& natTag = NfcTag::getInstance (); + + if (natTag.mTechLibNfcTypes[0] != NFC_PROTOCOL_ISO_DEP) + { + ALOGD ("%s: protocol: %d not ISO_DEP, do nothing", __FUNCTION__, natTag.mTechLibNfcTypes[0]); + return true; + } + + sRfInterfaceMutex.lock (); + ALOGD ("%s: new rf intf = %d, cur rf intf = %d", __FUNCTION__, rfInterface, sCurrentRfInterface); + + bool rVal = true; + if (rfInterface != sCurrentRfInterface) + { + if (rVal = (0 == reSelect(rfInterface))) + { + sCurrentRfInterface = rfInterface; + } + } + + sRfInterfaceMutex.unlock (); + return rVal; +} + +/******************************************************************************* +** +** Function: nativeNfcTag_doConnect_z +** +** Description: Connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doConnect_z (JNIEnv *e, jobject o, jint targetHandle) +{ + jint result = nativeNfcTag_doConnect (e, o, targetHandle); + return result == NFCSTATUS_SUCCESS ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doReconnect +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: Status code. +** +*******************************************************************************/ +static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + + tNFA_INTF_TYPE intf = NFA_INTERFACE_FRAME; + NfcTag& natTag = NfcTag::getInstance (); + + // this is only supported for type 2 or 4 (ISO_DEP) tags + if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP) + intf = NFA_INTERFACE_ISO_DEP; + else if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_T2T) + intf = NFA_INTERFACE_FRAME; + else + { + return 0; // success + } + + return reSelect(intf); +} + +/******************************************************************************* +** +** Function: nativeNfcTag_doReconnect_z +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doReconnect_z (JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + //do nothing as the tag has already been activated + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doHandleReconnect +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: Status code. +** +*******************************************************************************/ +static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHandle) +{ + ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); + return nativeNfcTag_doConnect (e, o, targetHandle); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doHandleReconnect_z +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doHandleReconnect_z (JNIEnv *e, jobject o, jint targetHandle) +{ + ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); + return nativeNfcTag_doConnect_z (e, o, targetHandle); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doDisconnect +** +** Description: Deactivate the RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doDisconnect (JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + struct nfc_jni_native_data *nat = getNative (0, 0); + tNFA_STATUS nfaStat = NFA_STATUS_OK; + + gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT; + + if (NfcTag::getInstance ().isActivated () == false) + { + ALOGD ("%s: tag already deactivated", __FUNCTION__); + goto TheEnd; + } + + nfaStat = NFA_Deactivate (FALSE); + if (nfaStat != NFA_STATUS_OK) + ALOGE ("%s: deactivate failed; error=0x%X", __FUNCTION__, nfaStat); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doTranseiveStatus +** +** Description: Receive the completion status of transceive operation. +** buf: Contains tag's response. +** bufLen: Length of buffer. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doTranseiveStatus (uint8_t* buf, uint32_t bufLen) +{ + ALOGD ("%s: data len=%d, waiting for transceive: %d", __FUNCTION__, bufLen, sWaitingForTransceive); + if (!sWaitingForTransceive) + return; + + sTransceiveDataLen = 0; + if (bufLen) + { + if (NULL == (sTransceiveData = (uint8_t *) malloc (bufLen))) + { + ALOGD ("%s: memory allocation error", __FUNCTION__); + } + else + { + memcpy (sTransceiveData, buf, sTransceiveDataLen = bufLen); + } + } + + { + SyncEventGuard g (sTransceiveEvent); + sTransceiveEvent.notifyOne (); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doTransceive +** +** Description: Send raw data to the tag; receive tag's response. +** e: JVM environment. +** o: Java object. +** raw: Not used. +** statusTargetLost: Whether tag responds or times out. +** +** Returns: Response from tag. +** +*******************************************************************************/ +static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + ALOGD ("%s: enter; raw=%u; timeout = %d", __FUNCTION__, raw, gGeneralTransceiveTimeout); + bool fNeedToSwitchBack = false; + nfc_jni_native_data *nat = getNative (0, 0); + bool waitOk = false; + uint8_t *buf = NULL; + uint32_t bufLen = 0; + jint *targetLost = NULL; + + if (! NfcTag::getInstance ().isActivated ()) + { + if (statusTargetLost) + { + targetLost = e->GetIntArrayElements (statusTargetLost, 0); + if (targetLost) + *targetLost = 1; //causes NFC service to throw TagLostException + e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); + } + ALOGD ("%s: tag not active", __FUNCTION__); + return NULL; + } + + NfcTag& natTag = NfcTag::getInstance (); + if (natTag.mNumTechList >= 2 && natTag.mTechList[0] == TARGET_TYPE_ISO14443_3A) + { + if (natTag.mTechList[1] == TARGET_TYPE_MIFARE_CLASSIC) + { + // MifareClassic tag, we do not support transeive for this + if (statusTargetLost) + { + targetLost = e->GetIntArrayElements (statusTargetLost, 0); + if (targetLost) + *targetLost = 2; //causes NFC service to throw IOException + e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); + } + ALOGD ("%s: transceive not supported for MifareClassic tag", __FUNCTION__); + return NULL; + } + } + + // get input buffer and length from java call + buf = (uint8_t *) e->GetByteArrayElements (data, NULL); + bufLen = (uint32_t) e->GetArrayLength (data); + + if (statusTargetLost) + { + targetLost = e->GetIntArrayElements (statusTargetLost, 0); + if (targetLost) + *targetLost = 0; //success, tag is still present + } + + sSwitchBackTimer.kill (); + jbyteArray result = NULL; + do + { + if (sNeedToSwitchRf) + { + // for ISO_DEP tags connected to NfcA or NfcB we need to be in FRAME interface + if (!switchRfInterface (NFA_INTERFACE_FRAME)) //NFA_INTERFACE_ISO_DEP + { + break; + } + fNeedToSwitchBack = true; + } + + sWaitingForTransceive = true; + sTransceiveDataLen = 0; + { + SyncEventGuard g (sTransceiveEvent); + tNFA_STATUS status = NFA_SendRawFrame (buf, bufLen); + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: fail send; error=%d", __FUNCTION__, status); + break; + } + waitOk = sTransceiveEvent.wait (gGeneralTransceiveTimeout); + } + + if (waitOk == false) //if timeout occured + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + if (targetLost) + *targetLost = 2; //causes NFC service to throw IOException + break; + } + + if (! NfcTag::getInstance ().isActivated ()) + { + ALOGE ("%s: already deactivated", __FUNCTION__); + if (targetLost) + *targetLost = 1; //causes NFC service to throw TagLostException + break; + } + + ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen); + if (sTransceiveDataLen) + { + // marshall data to java for return + result = e->NewByteArray (sTransceiveDataLen); + if (result != NULL) + { + e->SetByteArrayRegion (result, 0, sTransceiveDataLen, (jbyte *) sTransceiveData); + } + else + ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__); + + free (sTransceiveData); + sTransceiveData = NULL; + sTransceiveDataLen = 0; + } + } while (0); + + sWaitingForTransceive = false; + e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT); + if (targetLost) + e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); + + if (fNeedToSwitchBack) + { + // this timer proc will switch us back to ISO_DEP frame interface + sSwitchBackTimer.set (1500, switchBackTimerProc); + } + + ALOGD ("%s: exit", __FUNCTION__); + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doGetNdefType +** +** Description: Retrieve the type of tag. +** e: JVM environment. +** o: Java object. +** libnfcType: Type of tag represented by JNI. +** javaType: Not used. +** +** Returns: Type of tag represented by NFC Service. +** +*******************************************************************************/ +static jint nativeNfcTag_doGetNdefType (JNIEnv *e, jobject o, jint libnfcType, jint javaType) +{ + ALOGD ("%s: enter; libnfc type=%d; java type=%d", __FUNCTION__, libnfcType, javaType); + jint ndefType = NDEF_UNKNOWN_TYPE; + + // For NFA, libnfcType is mapped to the protocol value received + // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event. + switch (libnfcType) { + case NFA_PROTOCOL_T1T: + ndefType = NDEF_TYPE1_TAG; + break; + case NFA_PROTOCOL_T2T: + ndefType = NDEF_TYPE2_TAG;; + break; + case NFA_PROTOCOL_T3T: + ndefType = NDEF_TYPE3_TAG; + break; + case NFA_PROTOCOL_ISO_DEP: + ndefType = NDEF_TYPE4_TAG; + break; + case NFA_PROTOCOL_ISO15693: + ndefType = NDEF_UNKNOWN_TYPE; + break; + case NFA_PROTOCOL_INVALID: + ndefType = NDEF_UNKNOWN_TYPE; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + ALOGD ("%s: exit; ndef type=%d", __FUNCTION__, ndefType); + return ndefType; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doCheckNdefResult +** +** Description: Receive the result of checking whether the tag contains a NDEF +** message. Called by the NFA_NDEF_DETECT_EVT. +** status: Status of the operation. +** maxSize: Maximum size of NDEF message. +** currentSize: Current size of NDEF message. +** flags: Indicate various states. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint32_t currentSize, uint8_t flags) +{ + //this function's flags parameter is defined using the following macros + //in nfc/include/rw_api.h; + //#define RW_NDEF_FL_READ_ONLY 0x01 /* Tag is read only */ + //#define RW_NDEF_FL_FORMATED 0x02 /* Tag formated for NDEF */ + //#define RW_NDEF_FL_SUPPORTED 0x04 /* NDEF supported by the tag */ + //#define RW_NDEF_FL_UNKNOWN 0x08 /* Unable to find if tag is ndef capable/formated/read only */ + //#define RW_NDEF_FL_FORMATABLE 0x10 /* Tag supports format operation */ + + if (status == NFC_STATUS_BUSY) + { + ALOGE ("%s: stack is busy", __FUNCTION__); + return; + } + + if (!sCheckNdefWaitingForComplete) + { + ALOGE ("%s: not waiting", __FUNCTION__); + return; + } + + if (flags & RW_NDEF_FL_READ_ONLY) + ALOGD ("%s: flag read-only", __FUNCTION__); + if (flags & RW_NDEF_FL_FORMATED) + ALOGD ("%s: flag formatted for ndef", __FUNCTION__); + if (flags & RW_NDEF_FL_SUPPORTED) + ALOGD ("%s: flag ndef supported", __FUNCTION__); + if (flags & RW_NDEF_FL_UNKNOWN) + ALOGD ("%s: flag all unknown", __FUNCTION__); + if (flags & RW_NDEF_FL_FORMATABLE) + ALOGD ("%s: flag formattable", __FUNCTION__); + + sCheckNdefWaitingForComplete = JNI_FALSE; + sCheckNdefStatus = status; + sCheckNdefCapable = false; //assume tag is NOT ndef capable + if (sCheckNdefStatus == NFA_STATUS_OK) + { + //NDEF content is on the tag + sCheckNdefMaxSize = maxSize; + sCheckNdefCurrentSize = currentSize; + sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY; + sCheckNdefCapable = true; + } + else if (sCheckNdefStatus == NFA_STATUS_FAILED) + { + //no NDEF content on the tag + sCheckNdefMaxSize = 0; + sCheckNdefCurrentSize = 0; + sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY; + if ((flags & RW_NDEF_FL_UNKNOWN) == 0) //if stack understands the tag + { + if (flags & RW_NDEF_FL_SUPPORTED) //if tag is ndef capable + sCheckNdefCapable = true; + } + } + else + { + ALOGE ("%s: unknown status=0x%X", __FUNCTION__, status); + sCheckNdefMaxSize = 0; + sCheckNdefCurrentSize = 0; + sCheckNdefCardReadOnly = false; + } + sem_post (&sCheckNdefSem); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doCheckNdef +** +** Description: Does the tag contain a NDEF message? +** e: JVM environment. +** o: Java object. +** ndefInfo: NDEF info. +** +** Returns: Status code. +** +*******************************************************************************/ +static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + jint* ndef = NULL; + + ALOGD ("%s: enter", __FUNCTION__); + + /* Create the write semaphore */ + if (sem_init (&sCheckNdefSem, 0, 0) == -1) + { + ALOGE ("%s: Check NDEF semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + if (NfcTag::getInstance ().isActivated () == false) + { + ALOGE ("%s: tag not present", __FUNCTION__); + goto TheEnd; + } + + ALOGD ("%s: try NFA_RwDetectNDef", __FUNCTION__); + sCheckNdefWaitingForComplete = JNI_TRUE; + status = NFA_RwDetectNDef (); + + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_RwDetectNDef failed, status = %d", __FUNCTION__, status); + goto TheEnd; + } + + /* Wait for check NDEF completion status */ + if (sem_wait (&sCheckNdefSem)) + { + ALOGE ("%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + if (sCheckNdefStatus == NFA_STATUS_OK) + { + //stack found a NDEF message on the tag + ndef = e->GetIntArrayElements (ndefInfo, 0); + if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T) + ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize (); + else + ndef[0] = sCheckNdefMaxSize; + if (sCheckNdefCardReadOnly) + ndef[1] = NDEF_MODE_READ_ONLY; + else + ndef[1] = NDEF_MODE_READ_WRITE; + e->ReleaseIntArrayElements (ndefInfo, ndef, 0); + status = NFA_STATUS_OK; + } + else if (sCheckNdefStatus == NFA_STATUS_FAILED) + { + //stack did not find a NDEF message on the tag; + ndef = e->GetIntArrayElements (ndefInfo, 0); + if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T) + ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize (); + else + ndef[0] = sCheckNdefMaxSize; + if (sCheckNdefCardReadOnly) + ndef[1] = NDEF_MODE_READ_ONLY; + else + ndef[1] = NDEF_MODE_READ_WRITE; + e->ReleaseIntArrayElements (ndefInfo, ndef, 0); + status = NFA_STATUS_FAILED; + } + else + { + ALOGD ("%s: unknown status 0x%X", __FUNCTION__, sCheckNdefStatus); + } + +TheEnd: + /* Destroy semaphore */ + if (sem_destroy (&sCheckNdefSem)) + { + ALOGE ("%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + sCheckNdefWaitingForComplete = JNI_FALSE; + ALOGD ("%s: exit; status=%u", __FUNCTION__, status); + return status; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doCheckNdef_z +** +** Description: Does the tag contain a NDEF message? +** e: JVM environment. +** o: Java object. +** ndefInfo: NDEF info. +** +** Returns: True if tag contains a NDEF message. +** +*******************************************************************************/ +static bool nativeNfcTag_doCheckNdef_z (JNIEnv *e, jobject o, jintArray ndefInfo) +{ + ALOGD ("%s: enter", __FUNCTION__); + jint result = nativeNfcTag_doCheckNdef (e, o, ndefInfo); + bool retval = (result == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; + ALOGD ("%s: exit; detected NDEF=%u", __FUNCTION__, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_resetPresenceCheck +** +** Description: Reset variables related to presence-check. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_resetPresenceCheck () +{ + sCountTagAway = 0; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doPresenceCheckResult +** +** Description: Receive the result of presence-check. +** status: Result of presence-check. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status) +{ + if (status == NFA_STATUS_OK) + sCountTagAway = 0; + else + sCountTagAway++; + if (sCountTagAway > 0) + ALOGD ("%s: sCountTagAway=%d", __FUNCTION__, sCountTagAway); + sem_post (&sPresenceCheckSem); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doPresenceCheck +** +** Description: Check if the tag is in the RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: True if tag is in RF field. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doPresenceCheck (JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + tNFA_STATUS status = NFA_STATUS_OK; + jboolean isPresent = JNI_FALSE; + + if (nfcManager_isNfcActive() == false) + { + ALOGD ("%s: NFC is no longer active.", __FUNCTION__); + return JNI_FALSE; + } + + if (NfcTag::getInstance ().isActivated () == false) + { + ALOGD ("%s: tag already deactivated", __FUNCTION__); + return JNI_FALSE; + } + + if (sem_init (&sPresenceCheckSem, 0, 0) == -1) + { + ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + status = NFA_RwPresenceCheck (); + if (status == NFA_STATUS_OK) + { + if (sem_wait (&sPresenceCheckSem)) + { + ALOGE ("%s: failed to wait (errno=0x%08x)", __FUNCTION__, errno); + } + else + { + isPresent = (sCountTagAway > 3) ? JNI_FALSE : JNI_TRUE; + } + } + + if (sem_destroy (&sPresenceCheckSem)) + { + ALOGE ("Failed to destroy check NDEF semaphore (errno=0x%08x)", errno); + } + + if (isPresent == JNI_FALSE) + ALOGD ("%s: tag absent ????", __FUNCTION__); + return isPresent; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doIsNdefFormatable +** +** Description: Can tag be formatted to store NDEF message? +** e: JVM environment. +** o: Java object. +** libNfcType: Type of tag. +** uidBytes: Tag's unique ID. +** pollBytes: Data from activation. +** actBytes: Data from activation. +** +** Returns: True if formattable. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doIsNdefFormatable (JNIEnv *e, + jobject o, jint libNfcType, jbyteArray uidBytes, jbyteArray pollBytes, + jbyteArray actBytes) +{ + jboolean isFormattable = JNI_FALSE; + + switch (NfcTag::getInstance().getProtocol()) + { + case NFA_PROTOCOL_T1T: + case NFA_PROTOCOL_ISO15693: + isFormattable = JNI_TRUE; + break; + + case NFA_PROTOCOL_T2T: + isFormattable = NfcTag::getInstance().isMifareUltralight() ? JNI_TRUE : JNI_FALSE; + } + ALOGD("%s: is formattable=%u", __FUNCTION__, isFormattable); + return isFormattable; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doIsIsoDepNdefFormatable +** +** Description: Is ISO-DEP tag formattable? +** e: JVM environment. +** o: Java object. +** pollBytes: Data from activation. +** actBytes: Data from activation. +** +** Returns: True if formattable. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doIsIsoDepNdefFormatable (JNIEnv *e, jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + uint8_t uidFake[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + ALOGD ("%s", __FUNCTION__); + jbyteArray uidArray = e->NewByteArray (8); + e->SetByteArrayRegion (uidArray, 0, 8, (jbyte*) uidFake); + return nativeNfcTag_doIsNdefFormatable (e, o, 0, uidArray, pollBytes, actBytes); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doNdefFormat +** +** Description: Format a tag so it can store NDEF message. +** e: JVM environment. +** o: Java object. +** key: Not used. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doNdefFormat (JNIEnv *e, jobject o, jbyteArray key) +{ + ALOGD ("%s: enter", __FUNCTION__); + tNFA_STATUS status = NFA_STATUS_OK; + + sem_init (&sFormatSem, 0, 0); + sFormatOk = false; + status = NFA_RwFormatTag (); + if (status == NFA_STATUS_OK) + { + ALOGD ("%s: wait for completion", __FUNCTION__); + sem_wait (&sFormatSem); + status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED; + } + else + ALOGE ("%s: error status=%u", __FUNCTION__, status); + sem_destroy (&sFormatSem); + + ALOGD ("%s: exit", __FUNCTION__); + return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doMakeReadonlyResult +** +** Description: Receive the result of making a tag read-only. Called by the +** NFA_SET_TAG_RO_EVT. +** status: Status of the operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status) +{ + if (sMakeReadonlyWaitingForComplete != JNI_FALSE) + { + sMakeReadonlyWaitingForComplete = JNI_FALSE; + sMakeReadonlyStatus = status; + + sem_post (&sMakeReadonlySem); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doMakeReadonly +** +** Description: Make the tag read-only. +** e: JVM environment. +** o: Java object. +** key: Key to access the tag. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doMakeReadonly (JNIEnv *e, jobject o, jbyteArray key) +{ + jboolean result = JNI_FALSE; + tNFA_STATUS status; + + ALOGD ("%s", __FUNCTION__); + + /* Create the make_readonly semaphore */ + if (sem_init (&sMakeReadonlySem, 0, 0) == -1) + { + ALOGE ("%s: Make readonly semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + sMakeReadonlyWaitingForComplete = JNI_TRUE; + + // Hard-lock the tag (cannot be reverted) + status = NFA_RwSetTagReadOnly(TRUE); + + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_RwSetTagReadOnly failed, status = %d", __FUNCTION__, status); + goto TheEnd; + } + + /* Wait for check NDEF completion status */ + if (sem_wait (&sMakeReadonlySem)) + { + ALOGE ("%s: Failed to wait for make_readonly semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + if (sMakeReadonlyStatus == NFA_STATUS_OK) + { + result = JNI_TRUE; + } + +TheEnd: + /* Destroy semaphore */ + if (sem_destroy (&sMakeReadonlySem)) + { + ALOGE ("%s: Failed to destroy read_only semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + sMakeReadonlyWaitingForComplete = JNI_FALSE; + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_registerNdefTypeHandler +** +** Description: Register a callback to receive NDEF message from the tag +** from the NFA_NDEF_DATA_EVT. +** +** Returns: None +** +*******************************************************************************/ +//register a callback to receive NDEF message from the tag +//from the NFA_NDEF_DATA_EVT; +void nativeNfcTag_registerNdefTypeHandler () +{ + ALOGD ("%s", __FUNCTION__); + sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; + NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *) "", 0, ndefHandlerCallback); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_deregisterNdefTypeHandler +** +** Description: No longer need to receive NDEF message from the tag. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_deregisterNdefTypeHandler () +{ + ALOGD ("%s", __FUNCTION__); + NFA_DeregisterNDefTypeHandler (sNdefTypeHandlerHandle); + sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; +} + + +/***************************************************************************** +** +** JNI functions for Android 4.0.3 +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", (void *)nativeNfcTag_doConnect}, + {"doDisconnect", "()Z", (void *)nativeNfcTag_doDisconnect}, + {"doReconnect", "()I", (void *)nativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", (void *)nativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", (void *)nativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", (void *)nativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", (void *)nativeNfcTag_doCheckNdef}, + {"doRead", "()[B", (void *)nativeNfcTag_doRead}, + {"doWrite", "([B)Z", (void *)nativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", (void *)nativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", (void *)nativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", (void *)nativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", (void *)nativeNfcTag_doMakeReadonly}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeNfcTag +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeNfcTag (JNIEnv *e) +{ + GetNumValue (NAME_JNI_VERSION, &gJniVersion, sizeof(gJniVersion)); + ALOGD ("%s: enter, %s=%ld", __FUNCTION__, NAME_JNI_VERSION, gJniVersion); + ALOGD ("%s: exit; using %s", __FUNCTION__, gNativeNfcTagClassName); + return jniRegisterNativeMethods (e, gNativeNfcTagClassName, gMethods, NELEM (gMethods)); +} + + +} /* namespace android */ diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp new file mode 100644 index 0000000..16552a7 --- /dev/null +++ b/nci/jni/NativeP2pDevice.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NfcJniUtil.h" + + +namespace android +{ + + +extern char* gNativeP2pDeviceClassName; + + +static jboolean nativeP2pDeviceDoConnect (JNIEnv* e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return JNI_TRUE; +} + + +static jboolean nativeP2pDeviceDoDisconnect (JNIEnv* e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return JNI_TRUE; +} + + +static jbyteArray nativeP2pDeviceDoTransceive (JNIEnv* e, jobject o, jbyteArray data) +{ + ALOGD ("%s", __FUNCTION__); + return NULL; +} + + +static jbyteArray nativeP2pDeviceDoReceive (JNIEnv* e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return NULL; +} + + +static jboolean nativeP2pDeviceDoSend (JNIEnv* e, jobject o, jbyteArray buf) +{ + ALOGD ("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", (void *) nativeP2pDeviceDoConnect}, + {"doDisconnect", "()Z", (void *) nativeP2pDeviceDoDisconnect}, + {"doTransceive", "([B)[B", (void *) nativeP2pDeviceDoTransceive}, + {"doReceive", "()[B", (void *) nativeP2pDeviceDoReceive}, + {"doSend", "([B)Z", (void *) nativeP2pDeviceDoSend}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeP2pDevice +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeP2pDevice (JNIEnv* e) +{ + return jniRegisterNativeMethods (e, gNativeP2pDeviceClassName, + gMethods, NELEM(gMethods)); +} + + +} // namepspace android diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp new file mode 100755 index 0000000..09091ed --- /dev/null +++ b/nci/jni/NativeSecureElement.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NfcJniUtil.h" +#include "SecureElement.h" +#include "nfa_brcm_api.h" + + +namespace android +{ + + +extern void com_android_nfc_NfcManager_disableDiscovery (JNIEnv* e, jobject o); +extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode); +extern char* gNativeNfcSecureElementClassName; +extern int gGeneralTransceiveTimeout; + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doOpenSecureElementConnection +** +** Description: Connect to the secure element. +** e: JVM environment. +** o: Java object. +** +** Returns: Handle of secure element. 0 is failure. +** +*******************************************************************************/ +static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, jobject o) +{ + ALOGD("%s: enter", __FUNCTION__); + bool stat = true; + jint secElemHandle = 0; + + //if controller is not routing AND there is no pipe connected, + //then turn on the sec elem + if (! SecureElement::getInstance().isBusy()) + stat = SecureElement::getInstance().activate(0); + + if (stat) + { + //establish a pipe to sec elem + stat = SecureElement::getInstance().connectEE(); + if (stat) + secElemHandle = SecureElement::getInstance().mActiveEeHandle; + else + SecureElement::getInstance().deactivate (0); + } + +TheEnd: + ALOGD("%s: exit; return handle=0x%X", __FUNCTION__, secElemHandle); + return secElemHandle; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doDisconnectSecureElementConnection +** +** Description: Disconnect from the secure element. +** e: JVM environment. +** o: Java object. +** handle: Handle of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIEnv* e, jobject o, jint handle) +{ + ALOGD("%s: enter; handle=0x%04x", __FUNCTION__, handle); + bool stat = false; + + stat = SecureElement::getInstance().disconnectEE (handle); + + //if controller is not routing AND there is no pipe connected, + //then turn off the sec elem + if (! SecureElement::getInstance().isBusy()) + SecureElement::getInstance().deactivate (handle); + + ALOGD("%s: exit", __FUNCTION__); + return stat ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doTransceive +** +** Description: Send data to the secure element; retrieve response. +** e: JVM environment. +** o: Java object. +** handle: Secure element's handle. +** data: Data to send. +** +** Returns: Buffer of received data. +** +*******************************************************************************/ +static jbyteArray nativeNfcSecureElement_doTransceive (JNIEnv* e, jobject o, jint handle, jbyteArray data) +{ + UINT8* buf = NULL; + INT32 buflen = 0; + const INT32 recvBufferMaxSize = 1024; + UINT8 recvBuffer [recvBufferMaxSize]; + INT32 recvBufferActualSize = 0; + jbyteArray result = NULL; + + buf = (UINT8*) e->GetByteArrayElements (data, NULL); + buflen = e->GetArrayLength (data); + + ALOGD("%s: enter; handle=0x%X; buf len=%ld", __FUNCTION__, handle, buflen); + SecureElement::getInstance().transceive (buf, buflen, recvBuffer, recvBufferMaxSize, recvBufferActualSize, gGeneralTransceiveTimeout); + + //copy results back to java + result = e->NewByteArray (recvBufferActualSize); + if (result != NULL) + { + e->SetByteArrayRegion (result, 0, recvBufferActualSize, (jbyte *) recvBuffer); + } + + e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT); + ALOGD("%s: exit: recv len=%ld", __FUNCTION__, recvBufferActualSize); + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doGetUid +** +** Description: Get the secure element's unique ID. +** e: JVM environment. +** o: Java object. +** handle: Handle of secure element. +** +** Returns: Secure element's unique ID. +** +*******************************************************************************/ +static jbyteArray nativeNfcSecureElement_doGetUid (JNIEnv* e, jobject o, jint handle) +{ + ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle); + jbyteArray secureElementUid = NULL; + + SecureElement::getInstance ().getUiccId (handle, secureElementUid); + + ALOGD("%s: exit", __FUNCTION__); + return secureElementUid; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doGetTechList +** +** Description: Get a list of technologies that the secure element supports. +** e: JVM environment. +** o: Java object. +** handle: Handle of secure element. +** +** Returns: Array of technologies. +** +*******************************************************************************/ +static jintArray nativeNfcSecureElement_doGetTechList (JNIEnv* e, jobject o, jint handle) +{ + ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle); + jintArray techList = NULL; + + SecureElement::getInstance().getTechnologyList (handle, techList); + + ALOGD("%s: exit", __FUNCTION__); + return techList; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", (void *) nativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", (void *) nativeNfcSecureElement_doDisconnectSecureElementConnection}, + {"doTransceive", "(I[B)[B", (void *) nativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", (void *) nativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", (void *) nativeNfcSecureElement_doGetTechList}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeNfcSecureElement +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, gNativeNfcSecureElementClassName, + gMethods, NELEM(gMethods)); +} + + +} // namespace android + diff --git a/nci/jni/NfcJniUtil.cpp b/nci/jni/NfcJniUtil.cpp new file mode 100755 index 0000000..d989188 --- /dev/null +++ b/nci/jni/NfcJniUtil.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NfcJniUtil.h" +#include + + +/******************************************************************************* +** +** Function: JNI_OnLoad +** +** Description: Register all JNI functions with Java Virtual Machine. +** jvm: Java Virtual Machine. +** reserved: Not used. +** +** Returns: JNI version. +** +*******************************************************************************/ +jint JNI_OnLoad (JavaVM *jvm, void *reserved) +{ + ALOGD ("%s: enter", __FUNCTION__); + JNIEnv *e = NULL; + + // Check JNI version + if (jvm->GetEnv ((void **) &e, JNI_VERSION_1_6)) + return JNI_ERR; + + if (android::register_com_android_nfc_NativeNfcManager (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement (e) == -1) + return JNI_ERR; + ALOGD ("%s: exit", __FUNCTION__); + return JNI_VERSION_1_6; +} + + +namespace android +{ + + +/******************************************************************************* +** +** Function: nfc_jni_cache_object +** +** Description: +** +** Returns: Status code. +** +*******************************************************************************/ +int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj) +{ + jclass cls = NULL; + jobject obj = NULL; + jmethodID ctor = 0; + + cls = e->FindClass (className); + if(cls == NULL) + { + ALOGE ("%s: find class error", __FUNCTION__); + return -1; + } + + ctor = e->GetMethodID (cls, "", "()V"); + obj = e->NewObject (cls, ctor); + if (obj == NULL) + { + ALOGE ("%s: create object error", __FUNCTION__); + return -1; + } + + *cachedObj = e->NewGlobalRef (obj); + if (*cachedObj == NULL) + { + e->DeleteLocalRef (obj); + ALOGE ("%s: global ref error", __FUNCTION__); + return -1; + } + e->DeleteLocalRef (obj); + return 0; +} + + +/******************************************************************************* +** +** Function: nfc_jni_get_nfc_socket_handle +** +** Description: Get the value of "mHandle" member variable. +** e: JVM environment. +** o: Java object. +** +** Returns: Value of mHandle. +** +*******************************************************************************/ +int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o) +{ + jclass c = NULL; + jfieldID f = 0; + + c = e->GetObjectClass (o); + f = e->GetFieldID (c, "mHandle", "I"); + return e->GetIntField (o, f); +} + + +/******************************************************************************* +** +** Function: nfc_jni_get_nat +** +** Description: Get the value of "mNative" member variable. +** e: JVM environment. +** o: Java object. +** +** Returns: Pointer to the value of mNative. +** +*******************************************************************************/ +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c = NULL; + jfieldID f = 0; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + + +} // namespace android diff --git a/nci/jni/NfcJniUtil.h b/nci/jni/NfcJniUtil.h new file mode 100755 index 0000000..18e75de --- /dev/null +++ b/nci/jni/NfcJniUtil.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#define LOG_TAG "BrcmNfcJni" +#include +#include +#include +#include +extern "C" +{ + #include + #include +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 + + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + + +//define a few NXP error codes that NFC service expects; +//see external/libnfc-nxp/src/phLibNfcStatus.h; +//see external/libnfc-nxp/inc/phNfcStatus.h +#define NFCSTATUS_SUCCESS (0x0000) +#define NFCSTATUS_FAILED (0x00FF) + +//default general trasceive timeout in millisecond +#define DEFAULT_GENERAL_TRANS_TIMEOUT 1000 + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + int tech_mask; + + /* Tag detected */ + jobject tag; + + int tHandle; + int tProtocols[16]; + int handles[16]; +}; + + +extern "C" +{ + jint JNI_OnLoad(JavaVM *jvm, void *reserved); +} + + +namespace android +{ + int nfc_jni_cache_object (JNIEnv *e, const char *clsname, jobject *cached_obj); + int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o); + struct nfc_jni_native_data* nfc_jni_get_nat (JNIEnv *e, jobject o); + int register_com_android_nfc_NativeNfcManager (JNIEnv *e); + int register_com_android_nfc_NativeNfcTag (JNIEnv *e); + int register_com_android_nfc_NativeP2pDevice (JNIEnv *e); + int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e); + int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv *e); + int register_com_android_nfc_NativeLlcpSocket (JNIEnv *e); + int register_com_android_nfc_NativeNfcSecureElement (JNIEnv *e); +} // namespace android + diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp new file mode 100755 index 0000000..c135014 --- /dev/null +++ b/nci/jni/NfcTag.cpp @@ -0,0 +1,1229 @@ +/***************************************************************************** +** +** Name: NfcTag.cpp +** +** Description: Tag-reading, tag-writing operations. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "NfcTag.h" +extern "C" +{ + #include "rw_int.h" +} + +extern long gJniVersion; + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyNdefMessageListeners; +} + + +/******************************************************************************* +** +** Function: NfcTag +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +NfcTag::NfcTag () +: mNativeData (NULL), + mIsActivated (false), + mProtocol(NFC_PROTOCOL_UNKNOWN), + mNumTechList (0), + mtT1tMaxMessageSize (0), + mReadCompletedStatus (NFA_STATUS_OK) +{ + memset (mTechList, 0, sizeof(mTechList)); + memset (mTechHandles, 0, sizeof(mTechHandles)); + memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); + memset (mTechParams, 0, sizeof(mTechParams)); + mLastKovioUidLen = 0; + memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN); +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get a reference to the singleton NfcTag object. +** +** Returns: Reference to NfcTag object. +** +*******************************************************************************/ +NfcTag& NfcTag::getInstance () +{ + static NfcTag tag; + return tag; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Reset member variables. +** native: Native data. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::initialize (nfc_jni_native_data* native) +{ + mNativeData = native; + mIsActivated = false; + mProtocol = NFC_PROTOCOL_UNKNOWN; + mNumTechList = 0; + mtT1tMaxMessageSize = 0; + mReadCompletedStatus = NFA_STATUS_OK; + resetTechnologies (); +} + + +/******************************************************************************* +** +** Function: abort +** +** Description: Unblock all operations. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::abort () +{ + SyncEventGuard g (mReadCompleteEvent); + mReadCompleteEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: isActivated +** +** Description: Is tag activated? +** +** Returns: True if tag is activated. +** +*******************************************************************************/ +bool NfcTag::isActivated () +{ + return mIsActivated; +} + + +/******************************************************************************* +** +** Function: getProtocol +** +** Description: Get the protocol of the current tag. +** +** Returns: Protocol number. +** +*******************************************************************************/ +tNFC_PROTOCOL NfcTag::getProtocol() +{ + return mProtocol; +} + +/******************************************************************************* +** +** Function TimeDiff +** +** Description Computes time difference in milliseconds. +** +** Returns Time difference in milliseconds +** +*******************************************************************************/ +UINT32 TimeDiff(timespec start, timespec end) +{ + timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) + { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } + else + { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + + return (temp.tv_sec * 1000) + (temp.tv_nsec / 1000000); +} + +/******************************************************************************* +** +** Function: IsSameKovio +** +** Description: Checks if tag activate is the same (UID) Kovio tag previously +** activated. This is needed due to a problem with some Kovio +** tags re-activating multiple times. +** activationData: data from activation. +** +** Returns: true if the activation is from the same tag previously +** activated, false otherwise +** +*******************************************************************************/ +bool NfcTag::IsSameKovio(tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::IsSameKovio"; + ALOGD ("%s: enter", fn); + tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf; + + if (rfDetail.protocol != NFC_PROTOCOL_KOVIO) + return false; + + memcpy (&(mTechParams[0]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + if (mTechParams [0].mode != NFC_DISCOVERY_TYPE_POLL_KOVIO) + return false; + + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + bool rVal = false; + if (mTechParams[0].param.pk.uid_len == mLastKovioUidLen) + { + if (memcmp(mLastKovioUid, &mTechParams [0].param.pk.uid, mTechParams[0].param.pk.uid_len) == 0) + { + //same tag + if (TimeDiff(mLastKovioTime, now) < 500) + { + // same tag within 500 ms, ignore activation + rVal = true; + } + } + } + + // save Kovio tag info + if (!rVal) + { + if ((mLastKovioUidLen = mTechParams[0].param.pk.uid_len) > NFC_KOVIO_MAX_LEN) + mLastKovioUidLen = NFC_KOVIO_MAX_LEN; + memcpy(mLastKovioUid, mTechParams[0].param.pk.uid, mLastKovioUidLen); + } + mLastKovioTime = now; + ALOGD ("%s: exit, is same Kovio=%d", fn, rVal); + return rVal; +} + +/******************************************************************************* +** +** Function: discoverTechnologies +** +** Description: Discover the technologies that NFC service needs by interpreting +** the data strucutures from the stack. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::discoverTechnologies (activation)"; + ALOGD ("%s: enter", fn); + tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf; + + mNumTechList = 0; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + + switch (rfDetail.protocol) + { + case NFC_PROTOCOL_T1T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + break; + + case NFC_PROTOCOL_T2T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + // could be MifFare UL or Classic or Kovio + { + // need to look at first byte of uid to find manuf. + tNFC_RF_TECH_PARAMS tech_params; + memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + + if ((tech_params.param.pa.nfcid1[0] == 0x04 && rfDetail.rf_tech_param.param.pa.sel_rsp == 0) || + rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 || + rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08) + { + //Mifare Ultralight or mifare Classic + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0) + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API + else + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API + } + } + break; + + case NFC_PROTOCOL_T3T: + mTechList [mNumTechList] = TARGET_TYPE_FELICA; + break; + + case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API + if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + } + else if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + } + break; + + case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API + mTechList [mNumTechList] = TARGET_TYPE_ISO15693; + break; + + case NFC_PROTOCOL_KOVIO: + ALOGE ("%s: Kovio", fn); + mNumTechList--; // no tech classes for Kovio + break; + + default: + ALOGE ("%s: unknown protocol ????", fn); + mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN; + break; + } + + mNumTechList++; + for (int i=0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, + i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: discoverTechnologies +** +** Description: Discover the technologies that NFC service needs by interpreting +** the data strucutures from the stack. +** discoveryData: data from discovery events(s). +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::discoverTechnologies (tNFA_DISC_RESULT& discoveryData) +{ + static const char fn [] = "NfcTag::discoverTechnologies (discovery)"; + tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf; + + ALOGD ("%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn, discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList); + if (mNumTechList >= MAX_NUM_TECHNOLOGY) + { + ALOGE ("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY); + goto TheEnd; + } + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + + switch (discovery_ntf.protocol) + { + case NFC_PROTOCOL_T1T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + break; + + case NFC_PROTOCOL_T2T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + //type-2 tags are identitical to Mifare Ultralight, so Ultralight is also discovered + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + if (discovery_ntf.rf_tech_param.param.pa.sel_rsp == 0) + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API + else + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API + + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + break; + + case NFC_PROTOCOL_T3T: + mTechList [mNumTechList] = TARGET_TYPE_FELICA; + break; + + case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API + if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + } + else if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + } + break; + + case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API + mTechList [mNumTechList] = TARGET_TYPE_ISO15693; + break; + + default: + ALOGE ("%s: unknown protocol ????", fn); + mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN; + break; + } + + mNumTechList++; + if (discovery_ntf.more == FALSE) + { + for (int i=0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, + i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]); + } + } + +TheEnd: + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: createNativeNfcTag +** +** Description: Create a brand new Java NativeNfcTag object; +** fill the objects's member variables with data; +** notify NFC service; +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::createNativeNfcTag"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + jclass tag_cls = NULL; + jmethodID ctor = NULL; + jobject tag = NULL; + + //acquire a pointer to the Java virtual machine + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE("%s: jni env is null", fn); + goto TheEnd; + } + + tag_cls = e->GetObjectClass (mNativeData->cached_NfcTag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE("%s: failed to get class", fn); + goto TheEnd; + } + + //create a new Java NativeNfcTag object + ctor = e->GetMethodID (tag_cls, "", "()V"); + tag = e->NewObject (tag_cls, ctor); + + //fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes + fillNativeNfcTagMembers1 (e, tag_cls, tag); + + //fill NativeNfcTag's members: mHandle, mConnectedTechnology + fillNativeNfcTagMembers2 (e, tag_cls, tag, activationData); + + //fill NativeNfcTag's members: mTechPollBytes + fillNativeNfcTagMembers3 (e, tag_cls, tag, activationData); + + //fill NativeNfcTag's members: mTechActBytes + fillNativeNfcTagMembers4 (e, tag_cls, tag, activationData); + + //fill NativeNfcTag's members: mUid + fillNativeNfcTagMembers5 (e, tag_cls, tag, activationData); + + if (mNativeData->tag != NULL) { + e->DeleteGlobalRef (mNativeData->tag); + } + mNativeData->tag = e->NewGlobalRef (tag); + + //notify NFC service about this new tag + ALOGD ("%s: try notify nfc service", fn); + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyNdefMessageListeners, tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify nfc service", fn); + } + e->DeleteLocalRef (tag); + +TheEnd: + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers1 +** +** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes. +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers1"; + ALOGD ("%s", fn); + jfieldID f = NULL; + + //create objects that represent NativeNfcTag's member variables + jintArray techList = e->NewIntArray (mNumTechList); + jintArray handleList = e->NewIntArray (mNumTechList); + jintArray typeList = e->NewIntArray (mNumTechList); + + jint* technologies = e->GetIntArrayElements (techList, NULL); + jint* handles = e->GetIntArrayElements (handleList, NULL); + jint* types = e->GetIntArrayElements (typeList, NULL); + for (int i = 0; i < mNumTechList; i++) + { + mNativeData->tProtocols [i] = mTechLibNfcTypes [i]; + mNativeData->handles [i] = mTechHandles [i]; + technologies [i] = mTechList [i]; + handles [i] = mTechHandles [i]; + types [i] = mTechLibNfcTypes [i]; + } + e->ReleaseIntArrayElements (techList, technologies, 0); + e->ReleaseIntArrayElements (handleList, handles, 0); + e->ReleaseIntArrayElements (typeList, types, 0); + + f = e->GetFieldID (tag_cls, "mTechList", "[I"); + e->SetObjectField (tag, f, techList); + + f = e->GetFieldID (tag_cls, "mTechHandles", "[I"); + e->SetObjectField (tag, f, handleList); + + f = e->GetFieldID (tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField (tag, f, typeList); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers2 +** +** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology. +** The original Google's implementation is in set_target_pollBytes( +** in com_android_nfc_NativeNfcTag.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +//fill NativeNfcTag's members: mHandle, mConnectedTechnology +void NfcTag::fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers2"; + ALOGD ("%s", fn); + jfieldID f = NULL; + + f = e->GetFieldID (tag_cls, (gJniVersion >= 401) ? "mConnectedTechIndex" : "mConnectedTechnology", "I"); + e->SetIntField (tag, f, (jint) 0); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers3 +** +** Description: Fill NativeNfcTag's members: mTechPollBytes. +** The original Google's implementation is in set_target_pollBytes( +** in com_android_nfc_NativeNfcTag.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers3"; + jfieldID f = NULL; + jbyteArray pollBytes = e->NewByteArray (0); + jobjectArray techPollBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(pollBytes), 0); + int len = 0; + + for (int i = 0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d; rf tech params mode=%u", fn, i, mTechParams [i].mode); + switch (mTechParams [i].mode) + { + case NFC_DISCOVERY_TYPE_POLL_A: + case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_A: + case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE: + ALOGD ("%s: tech A", fn); + pollBytes = e->NewByteArray (2); + e->SetByteArrayRegion (pollBytes, 0, 2, + (jbyte*) mTechParams [i].param.pa.sens_res); + break; + + case NFC_DISCOVERY_TYPE_POLL_B: + case NFC_DISCOVERY_TYPE_POLL_B_PRIME: + case NFC_DISCOVERY_TYPE_LISTEN_B: + case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME: + if (mTechList [i] == TARGET_TYPE_ISO14443_3B) //is TagTechnology.NFC_B by Java API + { + /***************** + see NFC Forum Digital Protocol specification; section 5.6.2; + in SENSB_RES response, byte 6 through 9 is Application Data, byte 10-12 or 13 is Protocol Info; + used by public API: NfcB.getApplicationData(), NfcB.getProtocolInfo(); + *****************/ + ALOGD ("%s: tech B; TARGET_TYPE_ISO14443_3B", fn); + len = mTechParams [i].param.pb.sensb_res_len; + len = len - 4; //subtract 4 bytes for NFCID0 at byte 2 through 5 + pollBytes = e->NewByteArray (len); + e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) (mTechParams [i].param.pb.sensb_res+4)); + } + else + pollBytes = e->NewByteArray (0); + break; + + case NFC_DISCOVERY_TYPE_POLL_F: + case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_F: + case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE: + { + /**************** + see NFC Forum Type 3 Tag Operation Specification; sections 2.3.2, 2.3.1.2; + see NFC Forum Digital Protocol Specification; sections 6.6.2; + PMm: manufacture parameter; 8 bytes; + System Code: 2 bytes; + ****************/ + ALOGD ("%s: tech F", fn); + UINT8 result [10]; //return result to NFC service + memset (result, 0, sizeof(result)); + len = 10; + + /**** + for (int ii = 0; ii < mTechParams [i].param.pf.sensf_res_len; ii++) + { + ALOGD ("%s: tech F, sendf_res[%d]=%d (0x%x)", + fn, ii, mTechParams [i].param.pf.sensf_res[ii],mTechParams [i].param.pf.sensf_res[ii]); + } + ***/ + memcpy (result, mTechParams [i].param.pf.sensf_res + 8, 8); //copy PMm + if (activationData.params.t3t.num_system_codes > 0) //copy the first System Code + { + UINT16 systemCode = *(activationData.params.t3t.p_system_codes); + result [8] = (UINT8) (systemCode >> 8); + result [9] = (UINT8) systemCode; + ALOGD ("%s: tech F; sys code=0x%X 0x%X", fn, result [8], result [9]); + } + pollBytes = e->NewByteArray (len); + e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) result); + } + break; + + case NFC_DISCOVERY_TYPE_POLL_ISO15693: + case NFC_DISCOVERY_TYPE_LISTEN_ISO15693: + { + ALOGD ("%s: tech iso 15693", fn); + //iso 15693 response flags: 1 octet + //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet + //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags(); + uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid}; + pollBytes = e->NewByteArray (2); + e->SetByteArrayRegion (pollBytes, 0, 2, (jbyte *) data); + } + break; + + default: + ALOGE ("%s: tech unknown ????", fn); + pollBytes = e->NewByteArray(0); + break; + } //switch: every type of technology + e->SetObjectArrayElement (techPollBytes, i, pollBytes); + } //for: every technology in the array + f = e->GetFieldID (tag_cls, "mTechPollBytes", "[[B"); + e->SetObjectField (tag, f, techPollBytes); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers4 +** +** Description: Fill NativeNfcTag's members: mTechActBytes. +** The original Google's implementation is in set_target_activationBytes() +** in com_android_nfc_NativeNfcTag.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers4"; + jfieldID f = NULL; + jbyteArray actBytes = e->NewByteArray (0); + jobjectArray techActBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(actBytes), 0); + jbyteArray uid = NULL; + int len = 0; + + for (int i = 0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d", fn, i); + switch (mTechLibNfcTypes[i]) + { + case NFC_PROTOCOL_T1T: + { + ALOGD ("%s: T1T; tech A", fn); + actBytes = e->NewByteArray (1); + e->SetByteArrayRegion (actBytes, 0, 1, + (jbyte*) &mTechParams [i].param.pa.sel_rsp); + } + break; + + case NFC_PROTOCOL_T2T: + { + ALOGD ("%s: T2T; tech A", fn); + actBytes = e->NewByteArray (1); + e->SetByteArrayRegion (actBytes, 0, 1, + (jbyte*) &mTechParams [i].param.pa.sel_rsp); + } + break; + + case NFC_PROTOCOL_T3T: //felica + { + ALOGD ("%s: T3T; felica; tech F", fn); + //really, there is no data + actBytes = e->NewByteArray (0); + } + break; + + case NFC_PROTOCOL_ISO_DEP: //t4t + { + if (mTechList [i] == TARGET_TYPE_ISO14443_4) //is TagTechnology.ISO_DEP by Java API + { + if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + //see NFC Forum Digital Protocol specification, section 11.6.2, "RATS Response"; search for "historical bytes"; + //copy historical bytes into Java object; + //the public API, IsoDep.getHistoricalBytes(), returns this data; + if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP) + { + tNFC_INTF_PA_ISO_DEP& pa_iso = activationData.activate_ntf.intf_param.intf_param.pa_iso; + ALOGD ("%s: T4T; ISO_DEP for tech A; copy historical bytes; len=%u", fn, pa_iso.his_byte_len); + actBytes = e->NewByteArray (pa_iso.his_byte_len); + if (pa_iso.his_byte_len > 0) + e->SetByteArrayRegion (actBytes, 0, pa_iso.his_byte_len, (jbyte*) (pa_iso.his_byte)); + } + else + { + ALOGE ("%s: T4T; ISO_DEP for tech A; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type); + actBytes = e->NewByteArray (0); + } + } + else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) + { + //see NFC Forum Digital Protocol specification, section 12.6.2, "ATTRIB Response"; + //copy higher-layer response bytes into Java object; + //the public API, IsoDep.getHiLayerResponse(), returns this data; + if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP) + { + tNFC_INTF_PB_ISO_DEP& pb_iso = activationData.activate_ntf.intf_param.intf_param.pb_iso; + ALOGD ("%s: T4T; ISO_DEP for tech B; copy response bytes; len=%u", fn, pb_iso.hi_info_len); + actBytes = e->NewByteArray (pb_iso.hi_info_len); + if (pb_iso.hi_info_len > 0) + e->SetByteArrayRegion (actBytes, 0, pb_iso.hi_info_len, (jbyte*) (pb_iso.hi_info)); + } + else + { + ALOGE ("%s: T4T; ISO_DEP for tech B; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type); + actBytes = e->NewByteArray (0); + } + } + } + else if (mTechList [i] == TARGET_TYPE_ISO14443_3A) //is TagTechnology.NFC_A by Java API + { + ALOGD ("%s: T4T; tech A", fn); + actBytes = e->NewByteArray (1); + e->SetByteArrayRegion (actBytes, 0, 1, (jbyte*) &mTechParams [i].param.pa.sel_rsp); + } + else + { + actBytes = e->NewByteArray (0); + } + } //case NFC_PROTOCOL_ISO_DEP: //t4t + break; + + case NFC_PROTOCOL_15693: + { + ALOGD ("%s: tech iso 15693", fn); + //iso 15693 response flags: 1 octet + //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet + //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags(); + uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid}; + actBytes = e->NewByteArray (2); + e->SetByteArrayRegion (actBytes, 0, 2, (jbyte *) data); + } + break; + + default: + ALOGD ("%s: tech unknown ????", fn); + actBytes = e->NewByteArray (0); + break; + }//switch + e->SetObjectArrayElement (techActBytes, i, actBytes); + } //for: every technology in the array + f = e->GetFieldID (tag_cls, "mTechActBytes", "[[B"); + e->SetObjectField (tag, f, techActBytes); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers5 +** +** Description: Fill NativeNfcTag's members: mUid. +** The original Google's implementation is in nfc_jni_Discovery_notification_callback() +** in com_android_nfc_NativeNfcManager.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers5"; + jfieldID f = NULL; + int len = 0; + jbyteArray uid = NULL; + + switch (mTechParams [0].mode) + { + case NFC_DISCOVERY_TYPE_POLL_KOVIO: + ALOGD ("%s: Kovio", fn); + len = mTechParams [0].param.pk.uid_len; + uid = e->NewByteArray (len); + e->SetByteArrayRegion (uid, 0, len, + (jbyte*) &mTechParams [0].param.pk.uid); + break; + + case NFC_DISCOVERY_TYPE_POLL_A: + case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_A: + case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE: + ALOGD ("%s: tech A", fn); + len = mTechParams [0].param.pa.nfcid1_len; + uid = e->NewByteArray (len); + e->SetByteArrayRegion (uid, 0, len, + (jbyte*) &mTechParams [0].param.pa.nfcid1); + break; + + case NFC_DISCOVERY_TYPE_POLL_B: + case NFC_DISCOVERY_TYPE_POLL_B_PRIME: + case NFC_DISCOVERY_TYPE_LISTEN_B: + case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME: + ALOGD ("%s: tech B", fn); + uid = e->NewByteArray (NFC_NFCID0_MAX_LEN); + e->SetByteArrayRegion (uid, 0, NFC_NFCID0_MAX_LEN, + (jbyte*) &mTechParams [0].param.pb.nfcid0); + break; + + case NFC_DISCOVERY_TYPE_POLL_F: + case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_F: + case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE: + ALOGD ("%s: tech F", fn); + uid = e->NewByteArray (NFC_NFCID2_LEN); + e->SetByteArrayRegion (uid, 0, NFC_NFCID2_LEN, + (jbyte*) &mTechParams [0].param.pf.nfcid2); + break; + + case NFC_DISCOVERY_TYPE_POLL_ISO15693: + case NFC_DISCOVERY_TYPE_LISTEN_ISO15693: + { + ALOGD ("%s: tech iso 15693", fn); + jbyte data [I93_UID_BYTE_LEN]; //8 bytes + for (int i=0; iNewByteArray (I93_UID_BYTE_LEN); + e->SetByteArrayRegion (uid, 0, I93_UID_BYTE_LEN, data); + } + break; + + default: + ALOGE ("%s: tech unknown ????", fn); + uid = e->NewByteArray (0); + break; + } //if + f = e->GetFieldID(tag_cls, "mUid", "[B"); + e->SetObjectField(tag, f, uid); +} + + +/******************************************************************************* +** +** Function: isP2pDiscovered +** +** Description: Does the peer support P2P? +** +** Returns: True if the peer supports P2P. +** +*******************************************************************************/ +bool NfcTag::isP2pDiscovered () +{ + static const char fn [] = "NfcTag::isP2pDiscovered"; + bool retval = false; + + for (int i = 0; i < mNumTechList; i++) + { + if (mTechLibNfcTypes[i] == NFA_PROTOCOL_NFC_DEP) + { + //if remote device supports P2P + ALOGD ("%s: discovered P2P", fn); + retval = true; + break; + } + } + ALOGD ("%s: return=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: selectP2p +** +** Description: Select the preferred P2P technology if there is a choice. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::selectP2p() +{ + static const char fn [] = "NfcTag::selectP2p"; + UINT8 rfDiscoveryId = 0; + + for (int i = 0; i < mNumTechList; i++) + { + //if remote device does not support P2P, just skip it + if (mTechLibNfcTypes[i] != NFA_PROTOCOL_NFC_DEP) + continue; + + //if remote device supports tech F; + //tech F is preferred because it is faster than tech A + if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F_ACTIVE) ) + { + rfDiscoveryId = mTechHandles[i]; + break; //no need to search further + } + else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ) + { + //only choose tech A if tech F is unavailable + if (rfDiscoveryId == 0) + rfDiscoveryId = mTechHandles[i]; + } + } + + if (rfDiscoveryId > 0) + { + ALOGD ("%s: select P2P; target rf discov id=0x%X", fn, rfDiscoveryId); + tNFA_STATUS stat = NFA_Select (rfDiscoveryId, NFA_PROTOCOL_NFC_DEP, NFA_INTERFACE_NFC_DEP); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail select P2P; error=0x%X", fn, stat); + } + else + ALOGE ("%s: cannot find P2P", fn); + resetTechnologies (); +} + + +/******************************************************************************* +** +** Function: resetTechnologies +** +** Description: Clear all data related to the technology, protocol of the tag. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::resetTechnologies () +{ + static const char fn [] = "NfcTag::resetTechnologies"; + ALOGD ("%s", fn); + mNumTechList = 0; + memset (mTechList, 0, sizeof(mTechList)); + memset (mTechHandles, 0, sizeof(mTechHandles)); + memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); + memset (mTechParams, 0, sizeof(mTechParams)); +} + + +/******************************************************************************* +** +** Function: selectFirstTag +** +** Description: When multiple tags are discovered, just select the first one to activate. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::selectFirstTag () +{ + static const char fn [] = "NfcTag::selectFirstTag"; + ALOGD ("%s: nfa target h=0x%X; protocol=0x%X", + fn, mTechHandles [0], mTechLibNfcTypes [0]); + tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME; + + if (mTechLibNfcTypes [0] == NFA_PROTOCOL_ISO_DEP) + { + rf_intf = NFA_INTERFACE_ISO_DEP; + } + else if (mTechLibNfcTypes [0] == NFA_PROTOCOL_NFC_DEP) + rf_intf = NFA_INTERFACE_NFC_DEP; + else + rf_intf = NFA_INTERFACE_FRAME; + + tNFA_STATUS stat = NFA_Select (mTechHandles [0], mTechLibNfcTypes [0], rf_intf); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail select; error=0x%X", fn, stat); +} + + +/******************************************************************************* +** +** Function: getT1tMaxMessageSize +** +** Description: Get the maximum size (octet) that a T1T can store. +** +** Returns: Maximum size in octets. +** +*******************************************************************************/ +int NfcTag::getT1tMaxMessageSize () +{ + static const char fn [] = "NfcTag::getT1tMaxMessageSize"; + + if (mProtocol != NFC_PROTOCOL_T1T) + { + ALOGE ("%s: wrong protocol %u", fn, mProtocol); + return 0; + } + return mtT1tMaxMessageSize; +} + + +/******************************************************************************* +** +** Function: calculateT1tMaxMessageSize +** +** Description: Calculate type-1 tag's max message size based on header ROM bytes. +** activate: reference to activation data. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate) +{ + static const char fn [] = "NfcTag::calculateT1tMaxMessageSize"; + + //make sure the tag is type-1 + if (activate.activate_ntf.protocol != NFC_PROTOCOL_T1T) + { + mtT1tMaxMessageSize = 0; + return; + } + + //examine the first byte of header ROM bytes + switch (activate.params.t1t.hr[0]) + { + case RW_T1T_IS_TOPAZ96: + mtT1tMaxMessageSize = 90; + break; + case RW_T1T_IS_TOPAZ512: + mtT1tMaxMessageSize = 462; + break; + default: + ALOGE ("%s: unknown T1T HR0=%u", fn, activate.params.t1t.hr[0]); + mtT1tMaxMessageSize = 0; + break; + } +} + + +/******************************************************************************* +** +** Function: isMifareUltralight +** +** Description: Whether the currently activated tag is Mifare Ultralight. +** +** Returns: True if tag is Mifare Ultralight. +** +*******************************************************************************/ +bool NfcTag::isMifareUltralight () +{ + static const char fn [] = "NfcTag::isMifareUltralight"; + bool retval = false; + + for (int i =0; i < mNumTechList; i++) + { + if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + //see NFC Digital Protocol, section 4.6.3 (SENS_RES); section 4.8.2 (SEL_RES). + //see Mifare Type Identification Procedure, section 5.1 (ATQA), 5.2 (SAK). + if ( (mTechParams[i].param.pa.sens_res[0] == 0x44) && + (mTechParams[i].param.pa.sens_res[1] == 0) ) + { + // SyncEventGuard g (mReadCompleteEvent); + // mReadCompletedStatus = NFA_STATUS_BUSY; + // ALOGD ("%s: read block 0x10", fn); + // tNFA_STATUS stat = NFA_RwT2tRead (0x10); + // if (stat == NFA_STATUS_OK) + // mReadCompleteEvent.wait (); + // + // //if read-completion status is failure, then the tag is + // //definitely Mifare Ultralight; + // //if read-completion status is OK, then the tag is + // //definitely Mifare Ultralight C; + // retval = (mReadCompletedStatus == NFA_STATUS_FAILED); + retval = true; + } + break; + } + } + ALOGD ("%s: return=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Handle connection-related events. +** event: event code. +** data: pointer to event data. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) +{ + switch (event) + { + case NFA_DISC_RESULT_EVT: + { + tNFA_DISC_RESULT& disc_result = data->disc_result; + if (disc_result.status == NFA_STATUS_OK) + { + discoverTechnologies (disc_result); + } + } + break; + + case NFA_ACTIVATED_EVT: + // Only do tag detection if we are polling and it is not 'EE Direct RF' activation + // (which may happen when we are activated as a tag). + if (data->activated.activate_ntf.rf_tech_param.mode < NCI_DISCOVERY_TYPE_LISTEN_A + && data->activated.activate_ntf.intf_param.type != NFC_INTERFACE_EE_DIRECT_RF) + { + tNFA_ACTIVATED& activated = data->activated; + if (IsSameKovio(activated)) + break; + mIsActivated = true; + mProtocol = activated.activate_ntf.protocol; + calculateT1tMaxMessageSize (activated); + discoverTechnologies (activated); + createNativeNfcTag (activated); + } + break; + + case NFA_DEACTIVATED_EVT: + mIsActivated = false; + mProtocol = NFC_PROTOCOL_UNKNOWN; + resetTechnologies (); + break; + + case NFA_READ_CPLT_EVT: + { + SyncEventGuard g (mReadCompleteEvent); + mReadCompletedStatus = data->status; + mReadCompleteEvent.notifyOne (); + } + break; + } +} + diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h new file mode 100755 index 0000000..2b17553 --- /dev/null +++ b/nci/jni/NfcTag.h @@ -0,0 +1,357 @@ +/***************************************************************************** +** +** Name: NfcTag.h +** +** Description: Tag-reading, tag-writing operations. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include "SyncEvent.h" +#include "NfcJniUtil.h" +extern "C" +{ + #include "nfa_rw_api.h" +} + + +class NfcTag +{ +public: + static const int MAX_NUM_TECHNOLOGY = 10; //max number of technologies supported by one or more tags + int mTechList [MAX_NUM_TECHNOLOGY]; //array of NFC technologies according to NFC service + int mTechHandles [MAX_NUM_TECHNOLOGY]; //array of tag handles according to NFC service + int mTechLibNfcTypes [MAX_NUM_TECHNOLOGY]; //array of detailed tag types according to NFC service + int mNumTechList; //current number of NFC technologies in the list + + /******************************************************************************* + ** + ** Function: NfcTag + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + NfcTag (); + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get a reference to the singleton NfcTag object. + ** + ** Returns: Reference to NfcTag object. + ** + *******************************************************************************/ + static NfcTag& getInstance (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Reset member variables. + ** native: Native data. + ** Returns: None + ** + *******************************************************************************/ + void initialize (nfc_jni_native_data* native); + + + /******************************************************************************* + ** + ** Function: abort + ** + ** Description: Unblock all operations. + ** + ** Returns: None + ** + *******************************************************************************/ + void abort (); + + + /******************************************************************************* + ** + ** Function: connectionEventHandler + ** + ** Description: Handle connection-related events. + ** event: event code. + ** data: pointer to event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data); + + + /******************************************************************************* + ** + ** Function: isActivated + ** + ** Description: Is tag activated? + ** + ** Returns: True if tag is activated. + ** + *******************************************************************************/ + bool isActivated (); + + + /******************************************************************************* + ** + ** Function: getProtocol + ** + ** Description: Get the protocol of the current tag. + ** + ** Returns: Protocol number. + ** + *******************************************************************************/ + tNFC_PROTOCOL getProtocol (); + + + /******************************************************************************* + ** + ** Function: isP2pDiscovered + ** + ** Description: Does the peer support P2P? + ** + ** Returns: True if the peer supports P2P. + ** + *******************************************************************************/ + bool isP2pDiscovered (); + + + /******************************************************************************* + ** + ** Function: selectP2p + ** + ** Description: Select the preferred P2P technology if there is a choice. + ** + ** Returns: None + ** + *******************************************************************************/ + void selectP2p (); + + + /******************************************************************************* + ** + ** Function: selectFirstTag + ** + ** Description: When multiple tags are discovered, just select the first one to activate. + ** + ** Returns: None + ** + *******************************************************************************/ + void selectFirstTag (); + + + /******************************************************************************* + ** + ** Function: getT1tMaxMessageSize + ** + ** Description: Get the maximum size (octet) that a T1T can store. + ** + ** Returns: Maximum size in octets. + ** + *******************************************************************************/ + int getT1tMaxMessageSize (); + + + /******************************************************************************* + ** + ** Function: isMifareUltralight + ** + ** Description: Whether the currently activated tag is Mifare Ultralight. + ** + ** Returns: True if tag is Mifare Ultralight. + ** + *******************************************************************************/ + bool isMifareUltralight (); + +private: + nfc_jni_native_data* mNativeData; + bool mIsActivated; + tNFC_PROTOCOL mProtocol; + int mtT1tMaxMessageSize; //T1T max NDEF message size + tNFA_STATUS mReadCompletedStatus; + tNFC_RF_TECH_PARAMS mTechParams [MAX_NUM_TECHNOLOGY]; //array of technology parameters + SyncEvent mReadCompleteEvent; + int mLastKovioUidLen; // len of uid of last Kovio tag activated + struct timespec mLastKovioTime; // time of last Kovio tag activation + UINT8 mLastKovioUid[NFC_KOVIO_MAX_LEN]; // uid of last Kovio tag activated + + + /******************************************************************************* + ** + ** Function: IsSameKovio + ** + ** Description: Checks if tag activate is the same (UID) Kovio tag previously + ** activated. This is needed due to a problem with some Kovio + ** tags re-activating multiple times. + ** activationData: data from activation. + ** + ** Returns: true if the activation is from the same tag previously + ** activated, false otherwise + ** + *******************************************************************************/ + bool IsSameKovio(tNFA_ACTIVATED& activationData); + + /******************************************************************************* + ** + ** Function: discoverTechnologies + ** + ** Description: Discover the technologies that NFC service needs by interpreting + ** the data strucutures from the stack. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void discoverTechnologies (tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: discoverTechnologies + ** + ** Description: Discover the technologies that NFC service needs by interpreting + ** the data strucutures from the stack. + ** discoveryData: data from discovery events(s). + ** + ** Returns: None + ** + *******************************************************************************/ + void discoverTechnologies (tNFA_DISC_RESULT& discoveryData); + + + /******************************************************************************* + ** + ** Function: createNativeNfcTag + ** + ** Description: Create a brand new Java NativeNfcTag object; + ** fill the objects's member variables with data; + ** notify NFC service; + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void createNativeNfcTag (tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers1 + ** + ** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes. + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers2 + ** + ** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology. + ** The original Google's implementation is in set_target_pollBytes( + ** in com_android_nfc_NativeNfcTag.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers3 + ** + ** Description: Fill NativeNfcTag's members: mTechPollBytes. + ** The original Google's implementation is in set_target_pollBytes( + ** in com_android_nfc_NativeNfcTag.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers4 + ** + ** Description: Fill NativeNfcTag's members: mTechActBytes. + ** The original Google's implementation is in set_target_activationBytes() + ** in com_android_nfc_NativeNfcTag.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers5 + ** + ** Description: Fill NativeNfcTag's members: mUid. + ** The original Google's implementation is in nfc_jni_Discovery_notification_callback() + ** in com_android_nfc_NativeNfcManager.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: resetTechnologies + ** + ** Description: Clear all data related to the technology, protocol of the tag. + ** + ** Returns: None + ** + *******************************************************************************/ + void resetTechnologies (); + + + /******************************************************************************* + ** + ** Function: calculateT1tMaxMessageSize + ** + ** Description: Calculate type-1 tag's max message size based on header ROM bytes. + ** activate: reference to activation data. + ** + ** Returns: None + ** + *******************************************************************************/ + void calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate); +}; + diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp new file mode 100644 index 0000000..4c02da2 --- /dev/null +++ b/nci/jni/PeerToPeer.cpp @@ -0,0 +1,2158 @@ +/***************************************************************************** +** +** Name: PeerToPeer.cpp +** +** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include "PeerToPeer.h" +#include "NfcJniUtil.h" +#include "llcp_defs.h" +#include "config.h" + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; + extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; + extern void nativeNfcTag_registerNdefTypeHandler (); + extern void nativeNfcTag_deregisterNdefTypeHandler (); +} + + +PeerToPeer PeerToPeer::sP2p; +const std::string PeerToPeer::sSnepServiceName ("urn:nfc:sn:snep"); +const std::string PeerToPeer::sNppServiceName ("com.android.npp"); + + +/******************************************************************************* +** +** Function: PeerToPeer +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +PeerToPeer::PeerToPeer () +: mRemoteWKS (0), + mIsP2pListening (false), + mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A + | NFA_TECHNOLOGY_MASK_F + | NFA_TECHNOLOGY_MASK_A_ACTIVE + | NFA_TECHNOLOGY_MASK_F_ACTIVE), + mJniHandleSendingNppViaSnep (0), + mSnepRegHandle (NFA_HANDLE_INVALID), + mRcvFakeNppJniHandle (0), + mNppFakeOutBuffer (NULL), + mNppTotalLen (0), + mNppReadSoFar (0), + mNdefTypeHandlerHandle (NFA_HANDLE_INVALID), + mAppLogLevel (1), + mJniVersion (403) +{ + unsigned long num = 0; + memset (mServers, 0, sizeof(mServers)); + memset (mClients, 0, sizeof(mClients)); + if (GetNumValue ("APPL_TRACE_LEVEL", &num, sizeof (num))) + mAppLogLevel = num; + + if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) + mP2pListenTechMask = num; +} + + +/******************************************************************************* +** +** Function: ~PeerToPeer +** +** Description: Free all resources. +** +** Returns: None +** +*******************************************************************************/ +PeerToPeer::~PeerToPeer () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the singleton PeerToPeer object. +** +** Returns: Singleton PeerToPeer object. +** +*******************************************************************************/ +PeerToPeer& PeerToPeer::getInstance () +{ + return sP2p; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize member variables. +** jniVersion: JNI version. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::initialize (long jniVersion) +{ + ALOGD ("PeerToPeer::initialize"); + mJniVersion = jniVersion; +} + + +/******************************************************************************* +** +** Function: findServer +** +** Description: Find a PeerToPeer object by connection handle. +** nfaP2pServerHandle: Connectin handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pServer *PeerToPeer::findServer (tNFA_HANDLE nfaP2pServerHandle) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) + && (mServers[i]->mNfaP2pServerHandle == nfaP2pServerHandle) ) + { + return (mServers [i]); + } + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: findServer +** +** Description: Find a PeerToPeer object by connection handle. +** serviceName: service name. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pServer *PeerToPeer::findServer (tBRCM_JNI_HANDLE jniHandle) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) + && (mServers[i]->mJniHandle == jniHandle) ) + { + return (mServers [i]); + } + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: findServer +** +** Description: Find a PeerToPeer object by service name +** serviceName: service name. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pServer *PeerToPeer::findServer (const char *serviceName) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) && (mServers[i]->mServiceName.compare(serviceName) == 0) ) + return (mServers [i]); + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: registerServer +** +** Description: Let a server start listening for peer's connection request. +** jniHandle: Connection handle. +** serviceName: Server's service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *serviceName) +{ + static const char fn [] = "PeerToPeer::registerServer"; + ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle); + tNFA_STATUS stat = NFA_STATUS_OK; + P2pServer *pSrv = NULL; + UINT8 serverSap = NFA_P2P_ANY_SAP; + + // Check if already registered + if ((pSrv = findServer(serviceName)) != NULL) + { + ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle); + + // Update JNI handle + pSrv->mJniHandle = jniHandle; + return (true); + } + + for (int ii = 0; ii < sMax; ii++) + { + if (mServers[ii] == NULL) + { + pSrv = mServers[ii] = new P2pServer; + pSrv->mServiceName.assign (serviceName); + pSrv->mJniHandle = jniHandle; + + ALOGD ("%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName); + break; + } + } + + if (pSrv == NULL) + { + ALOGE ("%s: service name=%s no free entry", fn, serviceName); + return (false); + } + + /********************** + default values for all LLCP parameters: + - Local Link MIU (LLCP_MIU) + - Option parameter (LLCP_OPT_VALUE) + - Response Waiting Time Index (LLCP_WAITING_TIME) + - Local Link Timeout (LLCP_LTO_VALUE) + - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT) + - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT) + - Delay SYMM response (LLCP_DELAY_RESP_TIME) + - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) + - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) + ************************/ + stat = NFA_P2pSetLLCPConfig (LLCP_MIU, + LLCP_OPT_VALUE, + LLCP_WAITING_TIME, + LLCP_LTO_VALUE, + 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator + 0, //use 0 for infinite timeout for symmetry procedure when acting as target + LLCP_DELAY_RESP_TIME, + LLCP_DATA_LINK_CONNECTION_TOUT, + LLCP_DELAY_TIME_TO_SEND_FIRST_PDU); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat); + + if (sSnepServiceName.compare(serviceName) == 0) + serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 + + SyncEventGuard guard (pSrv->mListenEvent); + stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); + if (stat != NFA_STATUS_OK) + { + ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); + removeServer (jniHandle); + return (false); + } + ALOGD ("%s: wait for listen-completion event", fn); + // Wait for NFA_P2P_LISTEN_EVT + pSrv->mListenEvent.wait (); + + if (pSrv->mNfaP2pServerHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid server handle", fn); + removeServer (jniHandle); + return (false); + } + else + { + ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle); + return (true); + } +} + + +/******************************************************************************* +** +** Function: removeServer +** +** Description: Free resources related to a server. +** jniHandle: Connection handle. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::removeServer (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::removeServer"; + + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) && (mServers[i]->mJniHandle == jniHandle) ) + { + ALOGD ("%s: server jni_handle: %u; nfa_handle: 0x%04x; name: %s; index=%d", + fn, jniHandle, mServers[i]->mNfaP2pServerHandle, mServers[i]->mServiceName.c_str(), i); + + delete mServers [i]; + mServers [i] = NULL; + return; + } + } + ALOGE ("%s: unknown server jni handle: %u", fn, jniHandle); +} + + +/******************************************************************************* +** +** Function: llcpActivatedHandler +** +** Description: Receive LLLCP-activated event from stack. +** nat: JVM-related data. +** activated: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIVATED& activated) +{ + static const char fn [] = "PeerToPeer::llcpActivatedHandler"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + jclass tag_cls = NULL; + jobject tag = NULL; + jmethodID ctor = 0; + jfieldID f = 0; + + //no longer need to receive NDEF message from a tag + android::nativeNfcTag_deregisterNdefTypeHandler (); + + //register a type handler in case we need to send NDEF messages received from SNEP through NPP + mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; + NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *)"", 0, ndefTypeCallback); + + mRemoteWKS = activated.remote_wks; + + nat->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + ALOGD ("%s: get object class", fn); + tag_cls = e->GetObjectClass (nat->cached_P2pDevice); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail get p2p device", fn); + goto TheEnd; + } + + ALOGD ("%s: instantiate", fn); + /* New target instance */ + ctor = e->GetMethodID (tag_cls, "", "()V"); + tag = e->NewObject (tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID (tag_cls, "mMode", "I"); + + if (activated.is_initiator == TRUE) + { + ALOGD ("%s: p2p initiator", fn); + e->SetIntField (tag, f, (jint) MODE_P2P_INITIATOR); + } + else + { + ALOGD ("%s: p2p target", fn); + e->SetIntField (tag, f, (jint) MODE_P2P_TARGET); + } + + /* Set tag handle */ + f = e->GetFieldID (tag_cls, "mHandle", "I"); + e->SetIntField (tag, f, (jint) 0x1234); // ?? This handle is not used for anything + + if (nat->tag != NULL) + { + e->DeleteGlobalRef (nat->tag); + } + nat->tag = e->NewGlobalRef (tag); + + ALOGD ("%s: notify nfc service", fn); + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkActivation, tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + e->DeleteLocalRef (tag); + +TheEnd: + nat->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: llcpDeactivatedHandler +** +** Description: Receive LLLCP-deactivated event from stack. +** nat: JVM-related data. +** deactivated: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEACTIVATED& deactivated) +{ + static const char fn [] = "PeerToPeer::llcpDeactivatedHandler"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + + nat->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + ALOGD ("%s: notify nfc service", fn); + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkDeactivated, nat->tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + nat->vm->DetachCurrentThread (); + + //PeerToPeer no longer needs to handle NDEF data event + NFA_DeregisterNDefTypeHandler (mNdefTypeHandlerHandle); + mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; + + //let the tag-reading code handle NDEF data event + android::nativeNfcTag_registerNdefTypeHandler (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: accept +** +** Description: Accept a peer's request to connect. +** serverJniHandle: Server's handle. +** connJniHandle: Connection handle. +** maxInfoUnit: Maximum information unit. +** recvWindow: Receive window size. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow) +{ + static const char fn [] = "PeerToPeer::accept"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + NfaConn *pConn = NULL; + bool stat = false; + int ii = 0; + P2pServer *pSrv = NULL; + + ALOGD ("%s: enter; server jni handle: %u; conn jni handle: %u; maxInfoUnit: %d; recvWindow: %d", fn, + serverJniHandle, connJniHandle, maxInfoUnit, recvWindow); + + if ((pSrv = findServer (serverJniHandle)) == NULL) + { + ALOGE ("%s: unknown server jni handle: %u", fn, serverJniHandle); + return (false); + } + + // First, find a free connection block to handle the connection + for (ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++) + { + if (pSrv->mServerConn[ii] == NULL) + { + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; allocate server conn index: %u", fn, + serverJniHandle, connJniHandle, ii); + pSrv->mServerConn[ii] = new NfaConn; + pSrv->mServerConn[ii]->mJniHandle = connJniHandle; + break; + } + } + + if (ii == MAX_NFA_CONNS_PER_SERVER) + { + ALOGE ("%s: fail allocate connection block", fn); + return (false); + } + + { + // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection + SyncEventGuard guard (pSrv->mConnRequestEvent); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; wait for incoming connection", fn, + serverJniHandle, connJniHandle, ii); + pSrv->mConnRequestEvent.wait(); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X; got incoming connection", fn, + serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); + } + + // If we had gotten a message via SNEP, fake it out to be for NPP + if (mRcvFakeNppJniHandle == serverJniHandle) + { + ALOGD ("%s: server jni handle %u diverted to NPP fake receive on conn jni handle %u", fn, serverJniHandle, connJniHandle); + delete (pSrv->mServerConn[ii]); + pSrv->mServerConn[ii] = NULL; + mRcvFakeNppJniHandle = connJniHandle; + return (true); + } + + if (pSrv->mServerConn[ii]->mNfaConnHandle == NFA_HANDLE_INVALID) + { + delete (pSrv->mServerConn[ii]); + pSrv->mServerConn[ii] = NULL; + ALOGD ("%s: no handle assigned", fn); + return (false); + } + + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X; try accept", fn, + serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); + nfaStat = NFA_P2pAcceptConn (pSrv->mServerConn[ii]->mNfaConnHandle, maxInfoUnit, recvWindow); + + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat); + return (false); + } + + ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X", fn, + serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); + return (true); +} + + +/******************************************************************************* +** +** Function: deregisterServer +** +** Description: Stop a P2pServer from listening for peer. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::deregisterServer"; + ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pServer *pSrv = NULL; + + if ((pSrv = findServer (jniHandle)) == NULL) + { + ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service handle: %u", fn, jniHandle); + return (false); + } + + // Server does not call NFA_P2pDisconnect(), so unblock the accept() + SyncEventGuard guard (pSrv->mConnRequestEvent); + pSrv->mConnRequestEvent.notifyOne(); + + nfaStat = NFA_P2pDeregister (pSrv->mNfaP2pServerHandle); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: deregister error=0x%X", fn, nfaStat); + } + + removeServer (jniHandle); + + ALOGD ("%s: exit", fn); + return true; +} + + +/******************************************************************************* +** +** Function: createClient +** +** Description: Create a P2pClient object for a new out-bound connection. +** jniHandle: Connection handle. +** miu: Maximum information unit. +** rw: Receive window size. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) +{ + static const char fn [] = "PeerToPeer::createClient"; + int i = 0; + ALOGD ("%s: enter: jni h: %u miu: %u rw: %u", fn, jniHandle, miu, rw); + + for (i = 0; i < sMax; i++) + { + if (mClients[i] == NULL) + { + mClients [i] = new P2pClient; + + mClients [i]->mClientConn.mJniHandle = jniHandle; + mClients [i]->mClientConn.mMaxInfoUnit = miu; + mClients [i]->mClientConn.mRecvWindow = rw; + break; + } + } + + if (i == sMax) + { + ALOGE ("%s: fail", fn); + return (false); + } + + ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, mClients[i], jniHandle); + + SyncEventGuard guard (mClients[i]->mRegisteringEvent); + NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback); + mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT + + if (mClients[i]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, mClients[i]->mClientConn.mNfaConnHandle); + return (true); + } + else + { + ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, mClients[i]->mClientConn.mNfaConnHandle); + removeConn (jniHandle); + return (false); + } +} + + +/******************************************************************************* +** +** Function: removeConn +** +** Description: Free resources related to a connection. +** jniHandle: Connection handle. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::removeConn(tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn[] = "PeerToPeer::removeConn"; + int ii = 0, jj = 0; + + // If the connection is a for a client, delete the client itself + for (ii = 0; ii < sMax; ii++) + { + if (mClients[ii] && (mClients[ii]->mClientConn.mJniHandle == jniHandle)) + { + if (mClients[ii]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) + NFA_P2pDeregister (mClients[ii]->mNfaP2pClientHandle); + + delete mClients[ii]; + mClients[ii] = NULL; + ALOGD ("%s: deleted client handle: %u index: %u", fn, jniHandle, ii); + return; + } + } + + // If the connection is for a server, just delete the connection + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServers[ii]->mServerConn[jj] != NULL) + && (mServers[ii]->mServerConn[jj]->mJniHandle == jniHandle) ) + { + ALOGD ("%s: delete server conn jni h: %u; index: %d; server jni h: %u", + fn, mServers[ii]->mServerConn[jj]->mJniHandle, jj, mServers[ii]->mJniHandle); + delete mServers[ii]->mServerConn[jj]; + mServers[ii]->mServerConn[jj] = NULL; + return; + } + } + } + } + + if (jniHandle == mRcvFakeNppJniHandle) + { + ALOGD ("%s: Reset mRcvFakeNppJniHandle: %u", fn, jniHandle); + mRcvFakeNppJniHandle = 0; + if (mNppFakeOutBuffer != NULL) + { + free (mNppFakeOutBuffer); + mNppFakeOutBuffer = NULL; + } + } + else + ALOGE ("%s: could not find handle: %u", fn, jniHandle); +} + + +/******************************************************************************* +** +** Function: connectConnOriented +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** serviceName: Peer's service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName) +{ + static const char fn [] = "PeerToPeer::connectConnOriented"; + ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName); + + // If we are connecting to NPP and the other side supports SNEP, use SNEP + if ( (sNppServiceName.compare(serviceName)==0) && (mSnepRegHandle != NFA_HANDLE_INVALID) ) + { + P2pClient *pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + return (false); + } + + if (mJniHandleSendingNppViaSnep != 0) + { + ALOGE ("%s: SNEP already active, SNEP JNI handle: %u new JNI handle: %u", fn, mJniHandleSendingNppViaSnep, jniHandle); + return (false); + } + + // Save JNI Handle and try to connect to SNEP + mJniHandleSendingNppViaSnep = jniHandle; + + if (NFA_SnepConnect (mSnepRegHandle, "urn:nfc:sn:snep") == NFA_STATUS_OK) + { + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.wait(); + + // If the connect attempt failed, connection handle is invalid + if (pClient->mSnepConnHandle != NFA_HANDLE_INVALID) + { + // return true, as if we were connected. + pClient->mClientConn.mRemoteMaxInfoUnit = 248; + pClient->mClientConn.mRemoteRecvWindow = 1; + return (true); + } + } + mJniHandleSendingNppViaSnep = 0; + } + + // If here, we did not establish a SNEP connection + bool stat = createDataLinkConn (jniHandle, serviceName, 0); + ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); + return stat; +} + + +/******************************************************************************* +** +** Function: connectConnOriented +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** destinationSap: Peer's service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap) +{ + static const char fn [] = "PeerToPeer::connectConnOriented"; + ALOGD ("%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap); + bool stat = createDataLinkConn (jniHandle, NULL, destinationSap); + ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); + return stat; +} + + +/******************************************************************************* +** +** Function: createDataLinkConn +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** serviceName: Peer's service name. +** destinationSap: Peer's service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap) +{ + static const char fn [] = "PeerToPeer::createDataLinkConn"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pClient *pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + return (false); + } + + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mIsConnecting = true; + + if (serviceName) + nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle, + const_cast(serviceName), pClient->mClientConn.mMaxInfoUnit, + pClient->mClientConn.mRecvWindow); + else if (destinationSap) + nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap, + pClient->mClientConn.mMaxInfoUnit, pClient->mClientConn.mRecvWindow); + + if (nfaStat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient); + pClient->mConnectingEvent.wait(); + + if (pClient->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) + { + removeConn (jniHandle); + nfaStat = NFA_STATUS_FAILED; + } + else + pClient->mIsConnecting = false; + } + else + { + removeConn (jniHandle); + ALOGE ("%s: fail; error=0x%X", fn, nfaStat); + } + + ALOGD ("%s: exit", fn); + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: findClient +** +** Description: Find a PeerToPeer object with a client connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pClient *PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) +{ + for (int i = 0; i < sMax; i++) + { + if (mClients[i] && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findClient +** +** Description: Find a PeerToPeer object with a client connection handle. +** jniHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pClient *PeerToPeer::findClient (tBRCM_JNI_HANDLE jniHandle) +{ + for (int i = 0; i < sMax; i++) + { + if (mClients[i] && (mClients[i]->mClientConn.mJniHandle == jniHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findClientCon +** +** Description: Find a PeerToPeer object with a client connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pClient *PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) +{ + for (int i = 0; i < sMax; i++) + { + if (mClients[i] && (mClients[i]->mClientConn.mNfaConnHandle == nfaConnHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findConnection +** +** Description: Find a PeerToPeer object with a connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) +{ + int ii = 0, jj = 0; + + // First, look through all the client control blocks + for (ii = 0; ii < sMax; ii++) + { + if ( (mClients[ii] != NULL) + && (mClients[ii]->mClientConn.mNfaConnHandle == nfaConnHandle) ) + return (&mClients[ii]->mClientConn); + } + + // Not found yet. Look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServers[ii]->mServerConn[jj] != NULL) + && (mServers[ii]->mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) + return (mServers[ii]->mServerConn[jj]); + } + } + } + + // Not found... + return NULL; +} + + +/******************************************************************************* +** +** Function: findConnection +** +** Description: Find a PeerToPeer object with a connection handle. +** jniHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +NfaConn *PeerToPeer::findConnection (tBRCM_JNI_HANDLE jniHandle) +{ + int ii = 0, jj = 0; + + // First, look through all the client control blocks + for (ii = 0; ii < sMax; ii++) + { + if ( (mClients[ii] != NULL) + && (mClients[ii]->mClientConn.mJniHandle == jniHandle) ) + return (&mClients[ii]->mClientConn); + } + + // Not found yet. Look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServers[ii]->mServerConn[jj] != NULL) + && (mServers[ii]->mServerConn[jj]->mJniHandle == jniHandle) ) + return (mServers[ii]->mServerConn[jj]); + } + } + } + + // Not found... + return NULL; +} + + +/******************************************************************************* +** +** Function: send +** +** Description: Send data to peer. +** jniHandle: Handle of connection. +** buffer: Buffer of data. +** bufferLen: Length of data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) +{ + static const char fn [] = "PeerToPeer::send"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + NfaConn *pConn = NULL; + + if ((pConn = findConnection (jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X mJniHandleSendingNppViaSnep: %u", + fn, pConn->mJniHandle, pConn->mNfaConnHandle, mJniHandleSendingNppViaSnep); + + // Is this a SNEP fake-out + if (jniHandle == mJniHandleSendingNppViaSnep) + { + return (sendViaSnep(jniHandle, buffer, bufferLen)); + } + + nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + + while (nfaStat == NFA_STATUS_CONGESTED) + { + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.wait (); + + if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + return (false); + + nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + } + + if (nfaStat == NFA_STATUS_OK) + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle); + else + ALOGE ("%s: Data not sent; JNI handle: %u NFA Handle: 0x%04x error: 0x%04x", + fn, jniHandle, pConn->mNfaConnHandle, nfaStat); + + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: sendViaSnep +** +** Description: Send out-bound data to the stack's SNEP protocol. +** jniHandle: Handle of connection. +** buffer: Buffer of data. +** dataLen: Length of data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 dataLen) +{ + static const char fn [] = "PeerToPeer::sendViaSnep"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pClient *pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + mJniHandleSendingNppViaSnep = 0; + return (false); + } + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u mSnepNdefMsgLen: %lu mSnepNdefBufLen: %lu dataLen: %d", + fn, jniHandle, pClient->mSnepNdefMsgLen, pClient->mSnepNdefBufLen, dataLen); + + if (pClient->mSnepNdefMsgLen == 0) + { + pClient->mSnepNdefMsgLen = (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | buffer[9]; + if ((pClient->mSnepNdefBuf = (UINT8 *)malloc (pClient->mSnepNdefMsgLen + 1000)) == NULL) + { + ALOGE ("%s: can't malloc len: %lu", fn, pClient->mSnepNdefMsgLen); + mJniHandleSendingNppViaSnep = 0; + return (false); + } + buffer += 10; + dataLen -= 10; + } + + if ((pClient->mSnepNdefBufLen + dataLen) > pClient->mSnepNdefMsgLen) + { + ALOGE ("%s: len error mSnepNdefBufLen: %lu dataLen: %u mSnepNdefMsgLen: %lu", fn, + pClient->mSnepNdefBufLen, dataLen, pClient->mSnepNdefMsgLen); + mJniHandleSendingNppViaSnep = 0; + free (pClient->mSnepNdefBuf); + pClient->mSnepNdefBuf = NULL; + return (false); + } + + // Save the data in the buffer + memcpy (pClient->mSnepNdefBuf + pClient->mSnepNdefBufLen, buffer, dataLen); + + pClient->mSnepNdefBufLen += dataLen; + + // If we got all the data, send it via SNEP + if (pClient->mSnepNdefBufLen == pClient->mSnepNdefMsgLen) + { + ALOGD ("%s GKI_poolcount(2): %u GKI_poolfreecount(2): %u", fn, GKI_poolcount(2), GKI_poolfreecount(2)); + + nfaStat = NFA_SnepPut (pClient->mSnepConnHandle, pClient->mSnepNdefBufLen, pClient->mSnepNdefBuf); + + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_SnepPut failed, code: 0x%04x", fn, nfaStat); + mJniHandleSendingNppViaSnep = 0; + free (pClient->mSnepNdefBuf); + pClient->mSnepNdefBuf = NULL; + return (false); + } + + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.wait (); + + free (pClient->mSnepNdefBuf); + pClient->mSnepNdefBuf = NULL; + mJniHandleSendingNppViaSnep = 0; + return (pClient->mIsSnepSentOk); + } + return (true); +} + + +/******************************************************************************* +** +** Function: receive +** +** Description: Receive data from peer. +** jniHandle: Handle of connection. +** buffer: Buffer to store data. +** bufferLen: Max length of buffer. +** actualLen: Actual length received. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) +{ + static const char fn [] = "PeerToPeer::receive"; + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); + NfaConn *pConn = NULL; + + if (jniHandle == mRcvFakeNppJniHandle) + return (feedNppFromSnep(buffer, bufferLen, actualLen)); + + if ((pConn = findConnection (jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); + + // Only wait for data if data queue is empty. + if (pConn->mInboundQ.isEmpty()) + { + // And don't wait if we're disconnected. + if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + { + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.wait(); + } + + // If the connection was disconnected while we were blocked... + if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + { + ALOGD ("%s: already disconnected while waiting", fn); + return (false); + } + } + + bool stat = pConn->mInboundQ.dequeue (buffer, bufferLen, actualLen); + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; client h=0x%X stat=%u actual len=%u", fn, pConn->mNfaConnHandle, stat, actualLen); + return stat; +} + + +/******************************************************************************* +** +** Function: feedNppFromSnep +** +** Description: Send incomming data to the NFC service's NDEF Push Protocol. +** buffer: Buffer of data to send. +** bufferLen: Length of data in buffer. +** actualLen: Actual length sent. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) +{ + static const char fn [] = "PeerToPeer::feedNppFromSnep"; + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: mNppTotalLen: %lu mNppReadSoFar: %lu bufferLen: %u", + fn, mNppTotalLen, mNppReadSoFar, bufferLen); + + if (bufferLen > (mNppTotalLen - mNppReadSoFar)) + bufferLen = mNppTotalLen - mNppReadSoFar; + + memcpy (buffer, mNppFakeOutBuffer + mNppReadSoFar, bufferLen); + + mNppReadSoFar += bufferLen; + actualLen = bufferLen; + + if (mNppReadSoFar == mNppTotalLen) + { + ALOGD ("%s: entire message consumed", fn); + free (mNppFakeOutBuffer); + mNppFakeOutBuffer = NULL; + mRcvFakeNppJniHandle = 0; + } + return (true); +} + + +/******************************************************************************* +** +** Function: disconnectConnOriented +** +** Description: Disconnect a connection-oriented connection with peer. +** jniHandle: Handle of connection. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::disconnectConnOriented"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pClient *pClient = NULL; + NfaConn *pConn = NULL; + + ALOGD ("%s: enter; jni handle: %u", fn, jniHandle); + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + // If this is a client, he may not be connected yet, so unblock him just in case + if ( ((pClient = findClient(jniHandle)) != NULL) && (pClient->mIsConnecting) ) + { + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mConnectingEvent.notifyOne(); + return (true); + } + + { + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne (); //unblock send() if congested + } + { + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne (); //unblock receive() + } + + if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: try disconn nfa h=0x%04X", fn, pConn->mNfaConnHandle); + SyncEventGuard guard (pConn->mDisconnectingEvent); + nfaStat = NFA_P2pDisconnect (pConn->mNfaConnHandle, FALSE); + + if (nfaStat != NFA_STATUS_OK) + ALOGE ("%s: fail p2p disconnect", fn); + else + pConn->mDisconnectingEvent.wait(); + } + + mDisconnectMutex.lock (); + removeConn (jniHandle); + mDisconnectMutex.unlock (); + + ALOGD ("%s: exit; jni handle: %u", fn, jniHandle); + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: getRemoteMaxInfoUnit +** +** Description: Get peer's max information unit. +** jniHandle: Handle of the connection. +** +** Returns: Peer's max information unit. +** +*******************************************************************************/ +UINT16 PeerToPeer::getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit"; + NfaConn *pConn = NULL; + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find client jniHandle: %u", fn, jniHandle); + return 0; + } + ALOGD ("%s: jniHandle: %u MIU: %u", fn, jniHandle, pConn->mRemoteMaxInfoUnit); + return (pConn->mRemoteMaxInfoUnit); +} + + +/******************************************************************************* +** +** Function: getRemoteRecvWindow +** +** Description: Get peer's receive window size. +** jniHandle: Handle of the connection. +** +** Returns: Peer's receive window size. +** +*******************************************************************************/ +UINT8 PeerToPeer::getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::getRemoteRecvWindow"; + ALOGD ("%s: client jni handle: %u", fn, jniHandle); + NfaConn *pConn = NULL; + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find client", fn); + return 0; + } + return pConn->mRemoteRecvWindow; +} + + +/******************************************************************************* +** +** Function: enableP2pListening +** +** Description: Start/stop polling/listening to peer that supports P2P. +** isEnable: Is enable polling/listening? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::enableP2pListening (bool isEnable) +{ + static const char fn [] = "PeerToPeer::enableP2pListening"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + + ALOGD ("%s: enter isEnable: %u mIsP2pListening: %u", fn, isEnable, mIsP2pListening); + + // If request to enable P2P listening, and we were not already listening + if ( (isEnable == true) && (mIsP2pListening == false) && (mP2pListenTechMask != 0) ) + { + SyncEventGuard guard (mSetTechEvent); + if ((nfaStat = NFA_SetP2pListenTech (mP2pListenTechMask)) == NFA_STATUS_OK) + { + mSetTechEvent.wait (); + mIsP2pListening = true; + } + else + ALOGE ("%s: fail enable listen; error=0x%X", fn, nfaStat); + } + else if ( (isEnable == false) && (mIsP2pListening == true) ) + { + SyncEventGuard guard (mSetTechEvent); + // Request to disable P2P listening, check if it was enabled + if ((nfaStat = NFA_SetP2pListenTech(0)) == NFA_STATUS_OK) + { + mSetTechEvent.wait (); + mIsP2pListening = false; + } + else + ALOGE ("%s: fail disable listen; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit; mIsP2pListening: %u", fn, mIsP2pListening); +} + + +/******************************************************************************* +** +** Function: handleNfcOnOff +** +** Description: Handle events related to turning NFC on/off by the user. +** isOn: Is NFC turning on? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::handleNfcOnOff (bool isOn) +{ + static const char fn [] = "PeerToPeer::handleNfcOnOff"; + ALOGD ("%s: enter; is on=%u", fn, isOn); + tNFA_STATUS stat = NFA_STATUS_FAILED; + + mIsP2pListening = false; // In both cases, P2P will not be listening + + if (isOn) + { + // Start with no clients or servers + memset (mServers, 0, sizeof(mServers)); + memset (mClients, 0, sizeof(mClients)); + + //Android older than 4.0.3 (Ice Cream Sandwich) do not have SNEP in the + //NFC service, so the JNI and stack have to implement SNEP. + if (mJniVersion < 403) + { + { + SyncEventGuard guard (mSnepDefaultServerStartStopEvent); + stat = NFA_SnepStartDefaultServer (snepClientCallback); + if (stat == NFA_STATUS_OK) + mSnepDefaultServerStartStopEvent.wait (); //wait for NFA_SNEP_DEFAULT_SERVER_STARTED_EVT + else + ALOGE ("%s: fail start snep server; error=0x%X", fn, stat); + } + + { + SyncEventGuard guard (mSnepRegisterEvent); + stat = NFA_SnepRegisterClient (snepClientCallback); + if (stat == NFA_STATUS_OK) + mSnepRegisterEvent.wait (); //wait for NFA_SNEP_REG_EVT + else + ALOGE ("%s: fail register snep client; error=0x%X", fn, stat); + } + } + } + else + { + int ii = 0, jj = 0; + + // Disconnect through all the clients + for (ii = 0; ii < sMax; ii++) + { + if (mClients[ii] != NULL) + { + if (mClients[ii]->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) + { + SyncEventGuard guard (mClients[ii]->mConnectingEvent); + mClients[ii]->mConnectingEvent.notifyOne(); + } + else + { + mClients[ii]->mClientConn.mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mClients[ii]->mClientConn.mCongEvent); + mClients[ii]->mClientConn.mCongEvent.notifyOne (); //unblock send() + } + { + SyncEventGuard guard2 (mClients[ii]->mClientConn.mReadEvent); + mClients[ii]->mClientConn.mReadEvent.notifyOne (); //unblock receive() + } + } + } + } //loop + + // Now look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if (mServers[ii]->mServerConn[jj] != NULL) + { + mServers[ii]->mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mServers[ii]->mServerConn[jj]->mCongEvent); + mServers[ii]->mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested) + } + { + SyncEventGuard guard2 (mServers[ii]->mServerConn[jj]->mReadEvent); + mServers[ii]->mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive() + } + } + } + } + } //loop + + mJniHandleSendingNppViaSnep = 0; + mRcvFakeNppJniHandle = 0; + mSnepRegHandle = NFA_HANDLE_INVALID; + + if (mNppFakeOutBuffer != NULL) + { + free (mNppFakeOutBuffer); + mNppFakeOutBuffer = NULL; + } + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaServerCallback +** +** Description: Receive LLCP-related events from the stack. +** p2pEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) +{ + static const char fn [] = "PeerToPeer::nfaServerCallback"; + P2pServer *pSrv = NULL; + NfaConn *pConn = NULL; + + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent); + + switch (p2pEvent) + { + case NFA_P2P_LISTEN_EVT: // NFA_P2pRegisterServer() has started to listen + ALOGD ("%s: NFA_P2P_LISTEN_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, + eventData->listen.server_handle, eventData->listen.server_sap, eventData->listen.service_name); + + if ((pSrv = sP2p.findServer(eventData->listen.service_name)) == NULL) + { + ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service: %s", fn, eventData->listen.service_name); + } + else + { + SyncEventGuard guard (pSrv->mListenEvent); + pSrv->mNfaP2pServerHandle = eventData->listen.server_handle; + pSrv->mListenEvent.notifyOne(); //unblock registerServer() + } + break; + + case NFA_P2P_ACTIVATED_EVT: //remote device has activated + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); + break; + + case NFA_P2P_DEACTIVATED_EVT: + ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); + break; + + case NFA_P2P_CONN_REQ_EVT: + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; nfa server h=0x%04x; nfa conn h=0x%04x; remote sap=0x%02x", fn, + eventData->conn_req.server_handle, eventData->conn_req.conn_handle, eventData->conn_req.remote_sap); + + if ((pSrv = sP2p.findServer(eventData->conn_req.server_handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn); + return; + } + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u", fn, pSrv->mJniHandle); + + // Look for a connection block that is waiting (handle invalid) + if ((pConn = pSrv->findServerConnection(NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; server not listening", fn); + } + else + { + SyncEventGuard guard (pSrv->mConnRequestEvent); + pConn->mNfaConnHandle = eventData->conn_req.conn_handle; + pConn->mRemoteMaxInfoUnit = eventData->conn_req.remote_miu; + pConn->mRemoteRecvWindow = eventData->conn_req.remote_rw; + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u; conn jni h=%u; notify conn req", fn, pSrv->mJniHandle, pConn->mJniHandle); + pSrv->mConnRequestEvent.notifyOne(); //unblock accept() + } + break; + + case NFA_P2P_CONNECTED_EVT: + ALOGD ("%s: NFA_P2P_CONNECTED_EVT; h=0x%x remote sap=0x%X", fn, + eventData->connected.client_handle, eventData->connected.remote_sap); + break; + + case NFA_P2P_DISC_EVT: + ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason); + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle); + } + else + { + sP2p.mDisconnectMutex.lock (); + pConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); + SyncEventGuard guard3 (pConn->mDisconnectingEvent); + pConn->mDisconnectingEvent.notifyOne (); + ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn); + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne (); //unblock write (if congested) + ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn); + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne (); //unblock receive() + ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn); + } + sP2p.mDisconnectMutex.unlock (); + } + break; + + case NFA_P2P_DATA_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); + } + else + { + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + eventData->data.handle, eventData->data.remote_sap); + const int maxBufSize = 2 * 1024; + UINT8 buffer [maxBufSize]; + UINT32 actualDataLen = 0; + BOOLEAN isMoreData = TRUE; + while (isMoreData) + { + actualDataLen = 0; + isMoreData = FALSE; + tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) + pConn->mInboundQ.enqueue (buffer, actualDataLen); + } + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); + } + break; + + case NFA_P2P_CONGEST_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); + } + else + { + ALOGD ("%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + eventData->congest.handle, eventData->congest.is_congested); + + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } + break; + + default: + ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); + break; + } + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaClientCallback +** +** Description: Receive LLCP-related events from the stack. +** p2pEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) +{ + static const char fn [] = "PeerToPeer::nfaClientCallback"; + NfaConn *pConn = NULL; + P2pClient *pClient = NULL; + + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent); + + switch (p2pEvent) + { + case NFA_P2P_REG_CLIENT_EVT: + // Look for a client that is trying to register + if ((pClient = sP2p.findClient ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_REG_CLIENT_EVT: can't find waiting client", fn); + } + else + { + ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient); + + SyncEventGuard guard (pClient->mRegisteringEvent); + pClient->mNfaP2pClientHandle = eventData->reg_client.client_handle; + pClient->mRegisteringEvent.notifyOne(); + } + break; + + case NFA_P2P_ACTIVATED_EVT: + // Look for a client that is trying to register + if ((pClient = sP2p.findClient (eventData->activated.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_ACTIVATED_EVT: can't find client", fn); + } + else + { + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient); + } + break; + + case NFA_P2P_DEACTIVATED_EVT: + ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT: conn handle: 0x%X", fn, eventData->deactivated.handle); + break; + + case NFA_P2P_CONNECTED_EVT: + // Look for the client that is trying to connect + if ((pClient = sP2p.findClient (eventData->connected.client_handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONNECTED_EVT: can't find client: 0x%04x", fn, eventData->connected.client_handle); + } + else + { + ALOGD ("%s: NFA_P2P_CONNECTED_EVT; client_handle=0x%04x conn_handle: 0x%04x remote sap=0x%X pClient: 0x%p", fn, + eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient); + + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mClientConn.mNfaConnHandle = eventData->connected.conn_handle; + pClient->mClientConn.mRemoteMaxInfoUnit = eventData->connected.remote_miu; + pClient->mClientConn.mRemoteRecvWindow = eventData->connected.remote_rw; + pClient->mConnectingEvent.notifyOne(); //unblock createDataLinkConn() + } + break; + + case NFA_P2P_DISC_EVT: + ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason); + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL) + { + // If no connection, may be a client that is trying to connect + if ((pClient = sP2p.findClientCon ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle); + return; + } + // Unblock createDataLinkConn() + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mConnectingEvent.notifyOne(); + } + else + { + sP2p.mDisconnectMutex.lock (); + pConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); + SyncEventGuard guard3 (pConn->mDisconnectingEvent); + pConn->mDisconnectingEvent.notifyOne (); + ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn); + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); //unblock write (if congested) + ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn); + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); //unblock receive() + ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn); + } + sP2p.mDisconnectMutex.unlock (); + } + break; + + case NFA_P2P_DATA_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); + } + else + { + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + eventData->data.handle, eventData->data.remote_sap); + const int maxBufSize = 2 * 1024; + UINT8 buffer [maxBufSize]; + UINT32 actualDataLen = 0; + BOOLEAN isMoreData = TRUE; + while (isMoreData) + { + actualDataLen = 0; + isMoreData = FALSE; + tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) + pConn->mInboundQ.enqueue (buffer, actualDataLen); + } + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); + } + break; + + case NFA_P2P_CONGEST_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); + } + else + { + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + eventData->congest.handle, eventData->congest.is_congested); + + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } + break; + + default: + ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); + break; + } +} + + +/******************************************************************************* +** +** Function: snepClientCallback +** +** Description: Receive SNEP-related events from the stack. +** snepEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData) +{ + static const char fn [] = "PeerToPeer::snepClientCallback"; + P2pClient *pClient; + + switch (snepEvent) + { + case NFA_SNEP_REG_EVT: + { + ALOGD ("%s NFA_SNEP_REG_EVT Status: %u Handle: 0x%X", fn, eventData->reg.status, eventData->reg.reg_handle); + SyncEventGuard guard (sP2p.mSnepRegisterEvent); + if (eventData->reg.status == NFA_STATUS_OK) + sP2p.mSnepRegHandle = eventData->reg.reg_handle; + sP2p.mSnepRegisterEvent.notifyOne (); + break; + } + + case NFA_SNEP_ACTIVATED_EVT: + ALOGD ("%s NFA_SNEP_ACTIVATED_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + break; + + case NFA_SNEP_DEACTIVATED_EVT: + ALOGD ("%s NFA_SNEP_ACTIVATED_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + break; + + case NFA_SNEP_CONNECTED_EVT: + if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) + { + ALOGE ("%s: NFA_SNEP_CONNECTED_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + } + else + { + ALOGD ("%s NFA_SNEP_CONNECTED_EVT mJniHandleSendingNppViaSnep: %u ConnHandle: 0x%04x", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->connect.conn_handle); + + pClient->mSnepConnHandle = eventData->connect.conn_handle; + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.notifyOne(); + } + break; + + case NFA_SNEP_PUT_RESP_EVT: + if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) + { + ALOGE ("%s: NFA_SNEP_PUT_RESP_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + } + else + { + ALOGD ("%s NFA_SNEP_PUT_RESP_EVT mJniHandleSendingNppViaSnep: %u Result: 0x%X", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->put_resp.resp_code); + + pClient->mIsSnepSentOk = (eventData->put_resp.resp_code == NFA_SNEP_RESP_CODE_SUCCESS); + + NFA_SnepDisconnect (eventData->put_resp.conn_handle, FALSE); + + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.notifyOne(); + } + break; + + case NFA_SNEP_DISC_EVT: + if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) + { + ALOGE ("%s: NFA_SNEP_DISC_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + } + else + { + ALOGD ("%s NFA_SNEP_DISC_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + pClient->mSnepConnHandle = NFA_HANDLE_INVALID; + + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.notifyOne(); + } + break; + + case NFA_SNEP_DEFAULT_SERVER_STARTED_EVT: + { + ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STARTED_EVT", fn); + SyncEventGuard guard (sP2p.mSnepDefaultServerStartStopEvent); + sP2p.mSnepDefaultServerStartStopEvent.notifyOne(); //unblock NFA_SnepStartDefaultServer() + break; + } + + case NFA_SNEP_DEFAULT_SERVER_STOPPED_EVT: + { + ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STOPPED_EVT", fn); + SyncEventGuard guard (sP2p.mSnepDefaultServerStartStopEvent); + sP2p.mSnepDefaultServerStartStopEvent.notifyOne(); //unblock NFA_SnepStopDefaultServer() + break; + } + break; + + default: + ALOGE ("%s UNKNOWN EVENT: 0x%04x mJniHandleSendingNppViaSnep: %u", fn, snepEvent, sP2p.mJniHandleSendingNppViaSnep); + break; + } +} + + +/******************************************************************************* +** +** Function: ndefTypeCallback +** +** Description: Receive NDEF-related events from the stack. +** ndefEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::ndefTypeCallback (tNFA_NDEF_EVT ndefEvent, tNFA_NDEF_EVT_DATA *eventData) +{ + static const char fn [] = "PeerToPeer::ndefTypeCallback"; + P2pServer *pSvr = NULL; + + if (ndefEvent == NFA_NDEF_REGISTER_EVT) + { + tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg; + ALOGD ("%s NFA_NDEF_REGISTER_EVT Status: %u; h=0x%X", fn, ndef_reg.status, ndef_reg.ndef_type_handle); + sP2p.mNdefTypeHandlerHandle = ndef_reg.ndef_type_handle; + } + else if (ndefEvent == NFA_NDEF_DATA_EVT) + { + ALOGD ("%s NFA_NDEF_DATA_EVT Len: %lu", fn, eventData->ndef_data.len); + + if (sP2p.mRcvFakeNppJniHandle != 0) + { + ALOGE ("%s Got NDEF Data while busy, mRcvFakeNppJniHandle: %u", fn, sP2p.mRcvFakeNppJniHandle); + return; + } + + if ((pSvr = sP2p.findServer ("com.android.npp")) == NULL) + { + ALOGE ("%s Got NDEF Data but no NPP server listening", fn); + return; + } + + if ((sP2p.mNppFakeOutBuffer = (UINT8 *)malloc(eventData->ndef_data.len + 10)) == NULL) + { + ALOGE ("%s failed to malloc: %lu bytes", fn, eventData->ndef_data.len + 10); + return; + } + + sP2p.mNppFakeOutBuffer[0] = 0x01; + sP2p.mNppFakeOutBuffer[1] = 0x00; + sP2p.mNppFakeOutBuffer[2] = 0x00; + sP2p.mNppFakeOutBuffer[3] = 0x00; + sP2p.mNppFakeOutBuffer[4] = 0x01; + sP2p.mNppFakeOutBuffer[5] = 0x01; + sP2p.mNppFakeOutBuffer[6] = (UINT8)(eventData->ndef_data.len >> 24); + sP2p.mNppFakeOutBuffer[7] = (UINT8)(eventData->ndef_data.len >> 16); + sP2p.mNppFakeOutBuffer[8] = (UINT8)(eventData->ndef_data.len >> 8); + sP2p.mNppFakeOutBuffer[9] = (UINT8)(eventData->ndef_data.len); + + memcpy (&sP2p.mNppFakeOutBuffer[10], eventData->ndef_data.p_data, eventData->ndef_data.len); + + ALOGD ("%s NFA_NDEF_DATA_EVT Faking NPP on Server Handle: %u", fn, pSvr->mJniHandle); + + sP2p.mRcvFakeNppJniHandle = pSvr->mJniHandle; + sP2p.mNppTotalLen = eventData->ndef_data.len + 10; + sP2p.mNppReadSoFar = 0; + { + SyncEventGuard guard (pSvr->mConnRequestEvent); + pSvr->mConnRequestEvent.notifyOne(); + } + } + else + { + ALOGE ("%s UNKNOWN EVENT: 0x%X", fn, ndefEvent); + } + +} + + +/******************************************************************************* +** +** Function: getLogLevel +** +** Description: Get the diagnostic logging level. +** +** Returns: Log level; 0=no logging; 1=error only; 5=debug +** +*******************************************************************************/ +UINT32 PeerToPeer::getLogLevel () +{ + return mAppLogLevel; +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Receive events from the stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + switch (event) + { + case NFA_SET_P2P_LISTEN_TECH_EVT: + { + SyncEventGuard guard (mSetTechEvent); + mSetTechEvent.notifyOne(); //unblock NFA_SetP2pListenTech() + break; + } + } +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: P2pServer +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +P2pServer::P2pServer() +: mNfaP2pServerHandle (NFA_HANDLE_INVALID), + mJniHandle (0) +{ + memset (mServerConn, 0, sizeof(mServerConn)); +} + + +/******************************************************************************* +** +** Function: findServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +NfaConn *P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) +{ + int jj = 0; + + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) + return (mServerConn[jj]); + } + + // If here, not found + return (NULL); +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: P2pClient +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +P2pClient::P2pClient () +: mNfaP2pClientHandle (NFA_HANDLE_INVALID), + mIsConnecting (false), + mSnepConnHandle (NFA_HANDLE_INVALID), + mSnepNdefMsgLen (0), + mSnepNdefBufLen (0), + mSnepNdefBuf (NULL), + mIsSnepSentOk (false) +{ +} + + +/******************************************************************************* +** +** Function: ~P2pClient +** +** Description: Free all resources. +** +** Returns: None +** +*******************************************************************************/ +P2pClient::~P2pClient () +{ + if (mSnepNdefBuf) + free (mSnepNdefBuf); +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: NfaConn +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +NfaConn::NfaConn() +: mNfaConnHandle (NFA_HANDLE_INVALID), + mJniHandle (0), + mMaxInfoUnit (0), + mRecvWindow (0), + mRemoteMaxInfoUnit (0), + mRemoteRecvWindow (0) +{ +} + diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h new file mode 100644 index 0000000..00ead7f --- /dev/null +++ b/nci/jni/PeerToPeer.h @@ -0,0 +1,705 @@ +/***************************************************************************** +** +** Name: PeerToPeer.h +** +** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "SyncEvent.h" +#include "DataQueue.h" +#include "NfcJniUtil.h" +#include +extern "C" +{ + #include "nfa_p2p_api.h" + #include "nfa_snep_api.h" +} + +class P2pServer; +class P2pClient; +class NfaConn; +#define MAX_NFA_CONNS_PER_SERVER 5 +typedef unsigned int tBRCM_JNI_HANDLE; + + +/***************************************************************************** +** +** Name: PeerToPeer +** +** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. +** +*****************************************************************************/ +class PeerToPeer +{ +public: + + + /******************************************************************************* + ** + ** Function: PeerToPeer + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + PeerToPeer (); + + + /******************************************************************************* + ** + ** Function: ~PeerToPeer + ** + ** Description: Free all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~PeerToPeer (); + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get the singleton PeerToPeer object. + ** + ** Returns: Singleton PeerToPeer object. + ** + *******************************************************************************/ + static PeerToPeer& getInstance(); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize member variables. + ** jniVersion: JNI version. + ** + ** Returns: None + ** + *******************************************************************************/ + void initialize (long jniVersion); + + + /******************************************************************************* + ** + ** Function: llcpActivatedHandler + ** + ** Description: Receive LLLCP-activated event from stack. + ** nat: JVM-related data. + ** activated: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void llcpActivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_ACTIVATED& activated); + + + /******************************************************************************* + ** + ** Function: llcpDeactivatedHandler + ** + ** Description: Receive LLLCP-deactivated event from stack. + ** nat: JVM-related data. + ** deactivated: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void llcpDeactivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_DEACTIVATED& deactivated); + + + /******************************************************************************* + ** + ** Function: connectionEventHandler + ** + ** Description: Receive events from the stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: registerServer + ** + ** Description: Let a server start listening for peer's connection request. + ** jniHandle: Connection handle. + ** serviceName: Server's service name. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool registerServer (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); + + + /******************************************************************************* + ** + ** Function: deregisterServer + ** + ** Description: Stop a P2pServer from listening for peer. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool deregisterServer (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: accept + ** + ** Description: Accept a peer's request to connect. + ** serverJniHandle: Server's handle. + ** connJniHandle: Connection handle. + ** maxInfoUnit: Maximum information unit. + ** recvWindow: Receive window size. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow); + + + /******************************************************************************* + ** + ** Function: createClient + ** + ** Description: Create a P2pClient object for a new out-bound connection. + ** jniHandle: Connection handle. + ** miu: Maximum information unit. + ** rw: Receive window size. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw); + + + /******************************************************************************* + ** + ** Function: connectConnOriented + ** + ** Description: Estabish a connection-oriented connection to a peer. + ** jniHandle: Connection handle. + ** serviceName: Peer's service name. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); + + + /******************************************************************************* + ** + ** Function: connectConnOriented + ** + ** Description: Estabish a connection-oriented connection to a peer. + ** jniHandle: Connection handle. + ** destinationSap: Peer's service access point. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap); + + + /******************************************************************************* + ** + ** Function: send + ** + ** Description: Send data to peer. + ** jniHandle: Handle of connection. + ** buffer: Buffer of data. + ** bufferLen: Length of data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool send (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen); + + + /******************************************************************************* + ** + ** Function: receive + ** + ** Description: Receive data from peer. + ** jniHandle: Handle of connection. + ** buffer: Buffer to store data. + ** bufferLen: Max length of buffer. + ** actualLen: Actual length received. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); + + + /******************************************************************************* + ** + ** Function: disconnectConnOriented + ** + ** Description: Disconnect a connection-oriented connection with peer. + ** jniHandle: Handle of connection. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: getRemoteMaxInfoUnit + ** + ** Description: Get peer's max information unit. + ** jniHandle: Handle of the connection. + ** + ** Returns: Peer's max information unit. + ** + *******************************************************************************/ + UINT16 getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: getRemoteRecvWindow + ** + ** Description: Get peer's receive window size. + ** jniHandle: Handle of the connection. + ** + ** Returns: Peer's receive window size. + ** + *******************************************************************************/ + UINT8 getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: enableP2pListening + ** + ** Description: Start/stop polling/listening to peer that supports P2P. + ** isEnable: Is enable polling/listening? + ** + ** Returns: None + ** + *******************************************************************************/ + void enableP2pListening (bool isEnable); + + + /******************************************************************************* + ** + ** Function: handleNfcOnOff + ** + ** Description: Handle events related to turning NFC on/off by the user. + ** isOn: Is NFC turning on? + ** + ** Returns: None + ** + *******************************************************************************/ + void handleNfcOnOff (bool isOn); + + + /******************************************************************************* + ** + ** Function: getLogLevel + ** + ** Description: Get the diagnostic logging level. + ** + ** Returns: Log level; 0=no logging; 1=error only; 5=debug + ** + *******************************************************************************/ + UINT32 getLogLevel (); + +private: + static const int sMax = 10; + static PeerToPeer sP2p; + static const std::string sSnepServiceName; + static const std::string sNppServiceName; + UINT16 mRemoteWKS; // Peer's well known services + bool mIsP2pListening; // If P2P listening is enabled or not + tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask + tBRCM_JNI_HANDLE mJniHandleSendingNppViaSnep; + tNFA_HANDLE mSnepRegHandle; + tBRCM_JNI_HANDLE mRcvFakeNppJniHandle; + UINT8 *mNppFakeOutBuffer; + UINT32 mNppTotalLen; + UINT32 mNppReadSoFar; + tNFA_HANDLE mNdefTypeHandlerHandle; + UINT32 mAppLogLevel; + long mJniVersion; + + P2pServer *mServers [sMax]; + P2pClient *mClients [sMax]; + SyncEvent mSetTechEvent; // completion event for NFA_SetP2pListenTech() + SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer() + SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient() + Mutex mDisconnectMutex; // synchronize the disconnect operation + + + /******************************************************************************* + ** + ** Function: nfaServerCallback + ** + ** Description: Receive LLCP-related events from the stack. + ** p2pEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); + + + /******************************************************************************* + ** + ** Function: nfaClientCallback + ** + ** Description: Receive LLCP-related events from the stack. + ** p2pEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); + + + /******************************************************************************* + ** + ** Function: snepClientCallback + ** + ** Description: Receive SNEP-related events from the stack. + ** snepEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData); + + + /******************************************************************************* + ** + ** Function: ndefTypeCallback + ** + ** Description: Receive NDEF-related events from the stack. + ** ndefEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void ndefTypeCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *evetnData); + + + /******************************************************************************* + ** + ** Function: findServer + ** + ** Description: Find a PeerToPeer object by connection handle. + ** nfaP2pServerHandle: Connectin handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pServer *findServer (tNFA_HANDLE nfaP2pServerHandle); + + + /******************************************************************************* + ** + ** Function: findServer + ** + ** Description: Find a PeerToPeer object by connection handle. + ** serviceName: service name. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pServer *findServer (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: findServer + ** + ** Description: Find a PeerToPeer object by service name + ** serviceName: service name. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pServer *findServer (const char *serviceName); + + + /******************************************************************************* + ** + ** Function: removeServer + ** + ** Description: Free resources related to a server. + ** jniHandle: Connection handle. + ** + ** Returns: None + ** + *******************************************************************************/ + void removeServer (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: removeConn + ** + ** Description: Free resources related to a connection. + ** jniHandle: Connection handle. + ** + ** Returns: None + ** + *******************************************************************************/ + void removeConn (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: createDataLinkConn + ** + ** Description: Establish a connection-oriented connection to a peer. + ** jniHandle: Connection handle. + ** serviceName: Peer's service name. + ** destinationSap: Peer's service access point. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap); + + + /******************************************************************************* + ** + ** Function: findClient + ** + ** Description: Find a PeerToPeer object with a client connection handle. + ** nfaConnHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pClient *findClient (tNFA_HANDLE nfaConnHandle); + + + /******************************************************************************* + ** + ** Function: findClient + ** + ** Description: Find a PeerToPeer object with a client connection handle. + ** jniHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pClient *findClient (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: findClientCon + ** + ** Description: Find a PeerToPeer object with a client connection handle. + ** nfaConnHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pClient *findClientCon (tNFA_HANDLE nfaConnHandle); + + + /******************************************************************************* + ** + ** Function: findConnection + ** + ** Description: Find a PeerToPeer object with a connection handle. + ** nfaConnHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + NfaConn *findConnection (tNFA_HANDLE nfaConnHandle); + + + /******************************************************************************* + ** + ** Function: findConnection + ** + ** Description: Find a PeerToPeer object with a connection handle. + ** jniHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + NfaConn *findConnection (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: sendViaSnep + ** + ** Description: Send out-bound data to the stack's SNEP protocol. + ** jniHandle: Handle of connection. + ** buffer: Buffer of data. + ** dataLen: Length of data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen); + + + /******************************************************************************* + ** + ** Function: feedNppFromSnep + ** + ** Description: Send incomming data to the NFC service's NDEF Push Protocol. + ** buffer: Buffer of data to send. + ** bufferLen: Length of data in buffer. + ** actualLen: Actual length sent. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); +}; + + +/***************************************************************************** +** +** Name: NfaConn +** +** Description: Store information about a connection related to a peer. +** +*****************************************************************************/ +class NfaConn +{ +public: + tNFA_HANDLE mNfaConnHandle; // NFA handle of the P2P connection + tBRCM_JNI_HANDLE mJniHandle; // JNI handle of the P2P connection + UINT16 mMaxInfoUnit; + UINT8 mRecvWindow; + UINT16 mRemoteMaxInfoUnit; + UINT8 mRemoteRecvWindow; + DataQueue mInboundQ; // store inbound data + SyncEvent mReadEvent; // event for reading + SyncEvent mCongEvent; // event for congestion + SyncEvent mDisconnectingEvent; // event for disconnecting + + + /******************************************************************************* + ** + ** Function: NfaConn + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + NfaConn(); +}; + + +/***************************************************************************** +** +** Name: P2pServer +** +** Description: Store information about an in-bound connection from a peer. +** +*****************************************************************************/ +class P2pServer +{ +public: + tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server + tBRCM_JNI_HANDLE mJniHandle; // JNI Handle + SyncEvent mListenEvent; // for NFA_P2pRegisterServer() + SyncEvent mConnRequestEvent; // for accept() + std::string mServiceName; + NfaConn *mServerConn[MAX_NFA_CONNS_PER_SERVER]; + + /******************************************************************************* + ** + ** Function: P2pServer + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + P2pServer (); + + + /******************************************************************************* + ** + ** Function: findServerConnection + ** + ** Description: Find a P2pServer that has the handle. + ** nfaConnHandle: NFA connection handle. + ** + ** Returns: P2pServer object. + ** + *******************************************************************************/ + NfaConn *findServerConnection (tNFA_HANDLE nfaConnHandle); +}; + + +/***************************************************************************** +** +** Name: P2pClient +** +** Description: Store information about an out-bound connection to a peer. +** +*****************************************************************************/ +class P2pClient +{ +public: + tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client + bool mIsConnecting; // Set true while connecting + tNFA_HANDLE mSnepConnHandle; + UINT32 mSnepNdefMsgLen; // SNEP total NDEF message length + UINT32 mSnepNdefBufLen; // SNEP NDEF buffer length + UINT8 *mSnepNdefBuf; // SNEP NDEF Message + bool mIsSnepSentOk; // SNEP transmission status + NfaConn mClientConn; + SyncEvent mRegisteringEvent; // For client registration + SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap() + SyncEvent mSnepEvent; // To wait for SNEP completion + + /******************************************************************************* + ** + ** Function: P2pClient + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + P2pClient (); + + + /******************************************************************************* + ** + ** Function: ~P2pClient + ** + ** Description: Free all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~P2pClient (); +}; + diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp new file mode 100755 index 0000000..e5faaae --- /dev/null +++ b/nci/jni/PowerSwitch.cpp @@ -0,0 +1,410 @@ +/***************************************************************************** +** +** Name: PowerSwitch.cpp +** +** Description: Adjust the controller's power states. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include "PowerSwitch.h" +#include "NfcJniUtil.h" +#include "config.h" +#include "SecureElement.h" +#include "userial.h" + + +namespace android +{ + void doStartupConfig (); +} + + +PowerSwitch PowerSwitch::sPowerSwitch; + +/******************************************************************************* +** +** Function: PowerSwitch +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +PowerSwitch::PowerSwitch () +: mCurrLevel (UNKNOWN_LEVEL), + mScreenState (true), + mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN), + mDesiredScreenOffPowerState (0) +{ +} + + +/******************************************************************************* +** +** Function: ~PowerSwitch +** +** Description: Release all resources. +** +** Returns: None +** +*******************************************************************************/ +PowerSwitch::~PowerSwitch () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the singleton of this object. +** +** Returns: Reference to this object. +** +*******************************************************************************/ +PowerSwitch& PowerSwitch::getInstance () +{ + return sPowerSwitch; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +void PowerSwitch::initialize (PowerLevel level) +{ + static const char fn [] = "PowerSwitch::initialize"; + ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level); + + GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &mDesiredScreenOffPowerState, sizeof(mDesiredScreenOffPowerState)); + ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState); + + switch (level) + { + case FULL_POWER: + mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL; + mCurrLevel = level; + break; + + case UNKNOWN_LEVEL: + mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; + mCurrLevel = level; + break; + + default: + ALOGE ("%s: not handled", fn); + break; + } +} + + +/******************************************************************************* +** +** Function: getLevel +** +** Description: Get the current power level of the controller. +** +** Returns: Power level. +** +*******************************************************************************/ +PowerSwitch::PowerLevel PowerSwitch::getLevel () +{ + return mCurrLevel; +} + + +/******************************************************************************* +** +** Function: setLevel +** +** Description: Set the controller's power level. +** level: power level. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PowerSwitch::setLevel (PowerLevel newLevel) +{ + static const char fn [] = "PowerSwitch::setLevel"; + ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel); + bool retval = false; + + if (mCurrLevel == newLevel) + return true; + + switch (newLevel) + { + case FULL_POWER: + if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP) + retval = setPowerOffSleepState (false); + break; + + case LOW_POWER: + case POWER_OFF: + if (isPowerOffSleepFeatureEnabled()) + retval = setPowerOffSleepState (true); + else if (mDesiredScreenOffPowerState == 1) //.conf file desires full-power + { + mCurrLevel = FULL_POWER; + retval = true; + } + break; + + default: + ALOGE ("%s: not handled", fn); + break; + } + return retval; +} + +/******************************************************************************* +** +** Function: isScreenOn +** +** Description: Get the current platform power level. +** +** Returns: true if screen is on (locked or unlocked). +** +*******************************************************************************/ +bool PowerSwitch::isScreenOn () +{ + return mScreenState; +} + + +/******************************************************************************* +** +** Function: setScreenState +** +** Description: Set the Platform's screen state +** state: true for screen on, flase for screem off +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PowerSwitch::setScreenState(bool state) +{ + mScreenState = state; + return true; +} + +/******************************************************************************* +** +** Function: setPowerOffSleepState +** +** Description: Adjust controller's power-off-sleep state. +** sleep: whether to enter sleep state. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PowerSwitch::setPowerOffSleepState (bool sleep) +{ + static const char fn [] = "PowerSwitch::setPowerOffSleepState"; + ALOGD ("%s: enter; sleep=%u", fn, sleep); + tNFA_STATUS stat = NFA_STATUS_FAILED; + bool retval = false; + + if (sleep) //enter power-off-sleep state + { + //make sure the current power state is ON + if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP) + { + SyncEventGuard guard (mPowerStateEvent); + ALOGD ("%s: try power off", fn); + stat = NFA_PowerOffSleepMode (TRUE); + if (stat == NFA_STATUS_OK) + { + mPowerStateEvent.wait (); + mCurrLevel = LOW_POWER; + ALOGD ("%s: wait for userial close", fn); + int count = 0; + while (USERIAL_IsClosed() == FALSE) + { + //must wait for userial to close completely; + //otherwise there is a race condition when the next operation + //wants to go to full-power again; + count++; + usleep (5000); //5 milliseconds = 5 000 microseconds + } + ALOGD ("%s: userial close ok; count=%d", fn, count); + } + else + { + ALOGE ("%s: API fail; stat=0x%X", fn, stat); + goto TheEnd; + } + } + else + { + ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn, + deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); + goto TheEnd; + } + } + else //exit power-off-sleep state + { + //make sure the current power state is OFF + if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) + { + mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; + SyncEventGuard guard (mPowerStateEvent); + ALOGD ("%s: try full power", fn); + stat = NFA_PowerOffSleepMode (FALSE); + if (stat == NFA_STATUS_OK) + { + mPowerStateEvent.wait (); + if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) + { + ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn, + deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); + goto TheEnd; + } + android::doStartupConfig (); + mCurrLevel = FULL_POWER; + } + else + { + ALOGE ("%s: API fail; stat=0x%X", fn, stat); + goto TheEnd; + } + } + else + { + ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn, + deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); + goto TheEnd; + } + } + + retval = true; +TheEnd: + ALOGD ("%s: exit; return %u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: deviceMgtPowerStateToString +** +** Description: Decode power level to a string. +** deviceMgtPowerState: power level. +** +** Returns: Text representation of power level. +** +*******************************************************************************/ +const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState) +{ + switch (deviceMgtPowerState) + { + case NFA_DM_PWR_MODE_FULL: + return "DM-FULL"; + case NFA_DM_PWR_MODE_OFF_SLEEP: + return "DM-OFF"; + default: + return "DM-unknown????"; + } +} + + +/******************************************************************************* +** +** Function: powerLevelToString +** +** Description: Decode power level to a string. +** level: power level. +** +** Returns: Text representation of power level. +** +*******************************************************************************/ +const char* PowerSwitch::powerLevelToString (PowerLevel level) +{ + switch (level) + { + case UNKNOWN_LEVEL: + return "PS-UNKNOWN"; + case FULL_POWER: + return "PS-FULL"; + case LOW_POWER: + return "PS-LOW-POWER"; + case POWER_OFF: + return "PS-POWER-OFF"; + default: + return "PS-unknown????"; + } +} + + +/******************************************************************************* +** +** Function: abort +** +** Description: Abort and unblock currrent operation. +** +** Returns: None +** +*******************************************************************************/ +void PowerSwitch::abort () +{ + static const char fn [] = "PowerSwitch::abort"; + ALOGD ("%s", fn); + SyncEventGuard guard (mPowerStateEvent); + mPowerStateEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: deviceManagementCallback +** +** Description: Callback function for the stack. +** event: event ID. +** eventData: event's data. +** +** Returns: None +** +*******************************************************************************/ +void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData) +{ + static const char fn [] = "PowerSwitch::deviceManagementCallback"; + + switch (event) + { + case NFA_DM_PWR_MODE_CHANGE_EVT: + { + tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode; + ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=%u; device mgt power mode=%s (%u)", fn, + power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode), power_mode.power_mode); + SyncEventGuard guard (sPowerSwitch.mPowerStateEvent); + if (power_mode.status == NFA_STATUS_OK) + sPowerSwitch.mCurrDeviceMgtPowerState = power_mode.power_mode; + sPowerSwitch.mPowerStateEvent.notifyOne (); + } + break; + } +} + + +/******************************************************************************* +** +** Function: isPowerOffSleepFeatureEnabled +** +** Description: Whether power-off-sleep feature is enabled in .conf file. +** +** Returns: True if feature is enabled. +** +*******************************************************************************/ +bool PowerSwitch::isPowerOffSleepFeatureEnabled () +{ + return mDesiredScreenOffPowerState == 0; +} + diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h new file mode 100755 index 0000000..09197f1 --- /dev/null +++ b/nci/jni/PowerSwitch.h @@ -0,0 +1,236 @@ +/***************************************************************************** +** +** Name: PowerSwitch.h +** +** Description: Adjust the controller's power states. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "nfa_api.h" +#include "nfa_brcm_api.h" +#include "SyncEvent.h" + + +/***************************************************************************** +** +** Name: PowerSwitch +** +** Description: Adjust the controller's power states. +** +*****************************************************************************/ +class PowerSwitch +{ +public: + + + /******************************************************************************* + ** + ** Description: UNKNOWN_LEVEL: power level is unknown because the stack is off. + ** FULL_POWER: controller is in full-power state. + ** LOW_POWER: controller is in lower-power state. + ** + *******************************************************************************/ + enum PowerLevel {UNKNOWN_LEVEL, FULL_POWER, LOW_POWER, POWER_OFF}; + + /******************************************************************************* + ** + ** Description: Platform Power Level, copied from NativeNfcBrcmPowerMode.java. + ** UNKNOWN_LEVEL: power level is unknown. + ** POWER_OFF: The phone is turned OFF + ** SCREEN_OFF: The phone is turned ON but screen is OFF + ** SCREEN_ON_LOCKED: The phone is turned ON, screen is ON but user locked + ** SCREEN_ON_UNLOCKED: The phone is turned ON, screen is ON, and user unlocked + ** + *******************************************************************************/ + static const int PLATFORM_UNKNOWN_LEVEL = 0; + static const int PLATFORM_POWER_OFF = 1; + static const int PLATFORM_SCREEN_OFF = 2; + static const int PLATFORM_SCREEN_ON_LOCKED = 3; + static const int PLATFORM_SCREEN_ON_UNLOCKED = 4; + + static const int VBAT_MONITOR_ENABLED = 1; + static const int VBAT_MONITOR_PRIMARY_THRESHOLD = 5; + static const int VBAT_MONITOR_SECONDARY_THRESHOLD = 8; + /******************************************************************************* + ** + ** Function: PowerSwitch + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + PowerSwitch (); + + + /******************************************************************************* + ** + ** Function: ~PowerSwitch + ** + ** Description: Release all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~PowerSwitch (); + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get the singleton of this object. + ** + ** Returns: Reference to this object. + ** + *******************************************************************************/ + static PowerSwitch& getInstance (); + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + void initialize (PowerLevel level); + + + /******************************************************************************* + ** + ** Function: getLevel + ** + ** Description: Get the current power level of the controller. + ** + ** Returns: Power level. + ** + *******************************************************************************/ + PowerLevel getLevel (); + + + /******************************************************************************* + ** + ** Function: isScreenOn + ** + ** Description: Get the current screen state of the platform host. + ** + ** Returns: true if screen if on, (locked or unlocked). + ** + *******************************************************************************/ + bool isScreenOn (); + + + /******************************************************************************* + ** + ** Function: setLevel + ** + ** Description: Set the controller's power level. + ** level: power level. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool setLevel (PowerLevel level); + + /******************************************************************************* + ** + ** Function: setScreenState + ** + ** Description: Set the Platform's screen state + ** state: true for screen on, flase for screem off + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool setScreenState (bool state); + + /******************************************************************************* + ** + ** Function: abort + ** + ** Description: Abort and unblock currrent operation. + ** + ** Returns: None + ** + *******************************************************************************/ + void abort (); + + + /******************************************************************************* + ** + ** Function: deviceManagementCallback + ** + ** Description: Callback function for the stack. + ** event: event ID. + ** eventData: event's data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: isPowerOffSleepFeatureEnabled + ** + ** Description: Whether power-off-sleep feature is enabled in .conf file. + ** + ** Returns: True if feature is enabled. + ** + *******************************************************************************/ + bool isPowerOffSleepFeatureEnabled (); + +private: + PowerLevel mCurrLevel; + bool mScreenState; + UINT8 mCurrDeviceMgtPowerState; //device management power state; such as NFA_DM_PWR_STATE_??? + int mDesiredScreenOffPowerState; //read from .conf file; 0=power-off-sleep; 1=full power; 2=CE4 power + static PowerSwitch sPowerSwitch; //singleton object + static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown + SyncEvent mPowerStateEvent; + + + /******************************************************************************* + ** + ** Function: setPowerOffSleepState + ** + ** Description: Adjust controller's power-off-sleep state. + ** sleep: whether to enter sleep state. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool setPowerOffSleepState (bool sleep); + + + /******************************************************************************* + ** + ** Function: deviceMgtPowerStateToString + ** + ** Description: Decode power level to a string. + ** deviceMgtPowerState: power level. + ** + ** Returns: Text representation of power level. + ** + *******************************************************************************/ + const char* deviceMgtPowerStateToString (UINT8 deviceMgtPowerState); + + + /******************************************************************************* + ** + ** Function: powerLevelToString + ** + ** Description: Decode power level to a string. + ** level: power level. + ** + ** Returns: Text representation of power level. + ** + *******************************************************************************/ + const char* powerLevelToString (PowerLevel level); +}; diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp new file mode 100644 index 0000000..6f6eff7 --- /dev/null +++ b/nci/jni/RouteDataSet.cpp @@ -0,0 +1,546 @@ +/***************************************************************************** +** +** Name: RouteDataSet.cpp +** +** Description: Import and export general routing data using a XML file. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "RouteDataSet.h" +#include "libxml/xmlmemory.h" +#include +#include + +extern char bcm_nfc_location[]; + + +/******************************************************************************* +** +** Function: AidBuffer +** +** Description: Parse a string of hex numbers. Store result in an array of +** bytes. +** aid: string of hex numbers. +** +** Returns: None. +** +*******************************************************************************/ +AidBuffer::AidBuffer (std::string& aid) +: mBuffer (NULL), + mBufferLen (0) +{ + unsigned int num = 0; + const char delimiter = ':'; + std::string::size_type pos1 = 0; + std::string::size_type pos2 = aid.find_first_of (delimiter); + + //parse the AID string; each hex number is separated by a colon; + mBuffer = new UINT8 [aid.length()]; + while (true) + { + num = 0; + if (pos2 == std::string::npos) + { + sscanf (aid.substr(pos1).c_str(), "%x", &num); + mBuffer [mBufferLen] = (UINT8) num; + mBufferLen++; + break; + } + else + { + sscanf (aid.substr(pos1, pos2-pos1+1).c_str(), "%x", &num); + mBuffer [mBufferLen] = (UINT8) num; + mBufferLen++; + pos1 = pos2 + 1; + pos2 = aid.find_first_of (delimiter, pos1); + } + } +} + + +/******************************************************************************* +** +** Function: ~AidBuffer +** +** Description: Release all resources. +** +** Returns: None. +** +*******************************************************************************/ +AidBuffer::~AidBuffer () +{ + delete [] mBuffer; +} + + +/*******************************************************************************/ +/*******************************************************************************/ + + +const char* RouteDataSet::sConfigFile = "/param/route.xml"; + + +/******************************************************************************* +** +** Function: ~RouteDataSet +** +** Description: Release all resources. +** +** Returns: None. +** +*******************************************************************************/ +RouteDataSet::~RouteDataSet () +{ + deleteDatabase (); +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize resources. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool RouteDataSet::initialize () +{ + static const char fn [] = "RouteDataSet::initialize"; + ALOGD ("%s: enter", fn); + //check that the libxml2 version in use is compatible + //with the version the software has been compiled with + LIBXML_TEST_VERSION + ALOGD ("%s: exit; return=true", fn); + return true; +} + + +/******************************************************************************* +** +** Function: deleteDatabase +** +** Description: Delete all routes stored in all databases. +** +** Returns: None. +** +*******************************************************************************/ +void RouteDataSet::deleteDatabase () +{ + static const char fn [] = "RouteDataSet::deleteDatabase"; + ALOGD ("%s: default db size=%u; sec elem db size=%u", fn, mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size()); + Database::iterator it; + + for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++) + delete (*it); + mDefaultRouteDatabase.clear (); + + for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end(); it++) + delete (*it); + mSecElemRouteDatabase.clear (); +} + + +/******************************************************************************* +** +** Function: import +** +** Description: Import data from an XML file. Fill the databases. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool RouteDataSet::import () +{ + static const char fn [] = "RouteDataSet::import"; + ALOGD ("%s: enter", fn); + bool retval = false; + xmlDocPtr doc; + xmlNodePtr node1; + std::string strFilename(bcm_nfc_location); + strFilename += sConfigFile; + + deleteDatabase (); + + doc = xmlParseFile (strFilename.c_str()); + if (doc == NULL) + { + ALOGD ("%s: fail parse", fn); + goto TheEnd; + } + + node1 = xmlDocGetRootElement (doc); + if (node1 == NULL) + { + ALOGE ("%s: fail root element", fn); + goto TheEnd; + } + ALOGD ("%s: root=%s", fn, node1->name); + + node1 = node1->xmlChildrenNode; + while (node1) //loop through all elements in name, (const xmlChar*) "Route")==0) + { + xmlChar* value = xmlGetProp (node1, (const xmlChar*) "Type"); + if (value && (xmlStrcmp (value, (const xmlChar*) "SecElemSelectedRoutes") == 0)) + { + ALOGD ("%s: found SecElemSelectedRoutes", fn); + xmlNodePtr node2 = node1->xmlChildrenNode; + while (node2) //loop all elements in name, (const xmlChar*) "Proto")==0) + importProtocolRoute (node2, mSecElemRouteDatabase); + else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0) + importTechnologyRoute (node2, mSecElemRouteDatabase); + node2 = node2->next; + } //loop all elements in xmlChildrenNode; + while (node2) //loop all elements in name, (const xmlChar*) "Proto")==0) + importProtocolRoute (node2, mDefaultRouteDatabase); + else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0) + importTechnologyRoute (node2, mDefaultRouteDatabase); + node2 = node2->next; + } //loop all elements in next; + } //loop through all elements in name); + value = xmlGetProp (element, id); + if (value) + { + if (xmlStrcmp (value, (const xmlChar*) "T1T") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_T1T; + else if (xmlStrcmp (value, (const xmlChar*) "T2T") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_T2T; + else if (xmlStrcmp (value, (const xmlChar*) "T3T") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_T3T; + else if (xmlStrcmp (value, (const xmlChar*) "IsoDep") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP; + xmlFree (value); + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mProtocol); + } + + value = xmlGetProp (element, secElem); + if (value) + { + data->mNfaEeHandle = strtol ((char*) value, NULL, 16); + xmlFree (value); + data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE; + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle); + } + + value = xmlGetProp (element, switchOn); + if (value) + { + data->mSwitchOn = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, switchOff); + if (value) + { + data->mSwitchOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, batteryOff); + if (value) + { + data->mBatteryOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + database.push_back (data); +} + + +/******************************************************************************* +** +** Function: importTechnologyRoute +** +** Description: Parse data for technology routes. +** element: XML node for one technology route. +** database: store data in this database. +** +** Returns: None. +** +*******************************************************************************/ +void RouteDataSet::importTechnologyRoute (xmlNodePtr& element, Database& database) +{ + static const char fn [] = "RouteDataSet::importTechnologyRoute"; + const xmlChar* id = (const xmlChar*) "Id"; + const xmlChar* secElem = (const xmlChar*) "SecElem"; + const xmlChar* trueString = (const xmlChar*) "true"; + const xmlChar* switchOn = (const xmlChar*) "SwitchOn"; + const xmlChar* switchOff = (const xmlChar*) "SwitchOff"; + const xmlChar* batteryOff = (const xmlChar*) "BatteryOff"; + RouteDataForTechnology* data = new RouteDataForTechnology; + xmlChar* value = NULL; + + ALOGD_IF (sDebug, "%s: element=%s", fn, element->name); + value = xmlGetProp (element, id); + if (value) + { + if (xmlStrcmp (value, (const xmlChar*) "NfcA") == 0) + data->mTechnology = NFA_TECHNOLOGY_MASK_A; + else if (xmlStrcmp (value, (const xmlChar*) "NfcB") == 0) + data->mTechnology = NFA_TECHNOLOGY_MASK_B; + else if (xmlStrcmp (value, (const xmlChar*) "NfcF") == 0) + data->mTechnology = NFA_TECHNOLOGY_MASK_F; + xmlFree (value); + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mTechnology); + } + + value = xmlGetProp (element, secElem); + if (value) + { + data->mNfaEeHandle = strtol ((char*) value, NULL, 16); + xmlFree (value); + data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE; + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle); + } + + value = xmlGetProp (element, switchOn); + if (value) + { + data->mSwitchOn = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, switchOff); + if (value) + { + data->mSwitchOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, batteryOff); + if (value) + { + data->mBatteryOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + database.push_back (data); +} + + +/******************************************************************************* +** +** Function: deleteFile +** +** Description: Delete route data XML file. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool RouteDataSet::deleteFile () +{ + static const char fn [] = "RouteDataSet::deleteFile"; + std::string filename (bcm_nfc_location); + filename.append (sConfigFile); + int stat = remove (filename.c_str()); + ALOGD ("%s: exit %u", fn, stat==0); + return stat == 0; +} + + +/******************************************************************************* +** +** Function: getDatabase +** +** Description: Obtain a database of routing data. +** selection: which database. +** +** Returns: Pointer to database. +** +*******************************************************************************/ +RouteDataSet::Database* RouteDataSet::getDatabase (DatabaseSelection selection) +{ + switch (selection) + { + case DefaultRouteDatabase: + return &mDefaultRouteDatabase; + case SecElemRouteDatabase: + return &mSecElemRouteDatabase; + } + return NULL; +} + + +/******************************************************************************* +** +** Function: printDiagnostic +** +** Description: Print some diagnostic output. +** +** Returns: None. +** +*******************************************************************************/ +void RouteDataSet::printDiagnostic () +{ + static const char fn [] = "RouteDataSet::printDiagnostic"; + Database* db = getDatabase (DefaultRouteDatabase); + + ALOGD ("%s: default route database", fn); + for (Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + switch (routeData->mRouteType) + { + case RouteData::ProtocolRoute: + { + RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData; + ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol); + } + break; + } + } + + ALOGD ("%s: sec elem route database", fn); + db = getDatabase (SecElemRouteDatabase); + for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++) + { + RouteData* routeData = *iter2; + switch (routeData->mRouteType) + { + case RouteData::ProtocolRoute: + { + RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData; + ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol); + } + break; + case RouteData::TechnologyRoute: + { + RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData; + ALOGD ("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology); + } + break; + } + } +} diff --git a/nci/jni/RouteDataSet.h b/nci/jni/RouteDataSet.h new file mode 100644 index 0000000..23fd958 --- /dev/null +++ b/nci/jni/RouteDataSet.h @@ -0,0 +1,299 @@ +/***************************************************************************** +** +** Name: RouteDataSet.h +** +** Description: Import and export general routing data using a XML file. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "NfcJniUtil.h" +#include "nfa_api.h" +#include +#include +#include + + +/***************************************************************************** +** +** Name: RouteData +** +** Description: Base class for every kind of route data. +** +*****************************************************************************/ +class RouteData +{ +public: + enum RouteType {ProtocolRoute, TechnologyRoute}; + RouteType mRouteType; + +protected: + RouteData (RouteType routeType) : mRouteType (routeType) + {} +}; + + + + +/***************************************************************************** +** +** Name: RouteDataForProtocol +** +** Description: Data for protocol routes. +** +*****************************************************************************/ +class RouteDataForProtocol : public RouteData +{ +public: + int mNfaEeHandle; //for example 0x4f3, 0x4f4 + bool mSwitchOn; + bool mSwitchOff; + bool mBatteryOff; + tNFA_PROTOCOL_MASK mProtocol; + + RouteDataForProtocol () : RouteData (ProtocolRoute), mNfaEeHandle (NFA_HANDLE_INVALID), + mSwitchOn (false), mSwitchOff (false), mBatteryOff (false), + mProtocol (0) + {} +}; + + +/***************************************************************************** +** +** Name: RouteDataForTechnology +** +** Description: Data for technology routes. +** +*****************************************************************************/ +class RouteDataForTechnology : public RouteData +{ +public: + int mNfaEeHandle; //for example 0x4f3, 0x4f4 + bool mSwitchOn; + bool mSwitchOff; + bool mBatteryOff; + tNFA_TECHNOLOGY_MASK mTechnology; + + RouteDataForTechnology () : RouteData (TechnologyRoute), mNfaEeHandle (NFA_HANDLE_INVALID), + mSwitchOn (false), mSwitchOff (false), mBatteryOff (false), + mTechnology (0) + {} +}; + + +/*****************************************************************************/ +/*****************************************************************************/ + + +/***************************************************************************** +** +** Name: AidBuffer +** +** Description: Buffer to store AID after converting a string of hex +** values to bytes. +** +*****************************************************************************/ +class AidBuffer +{ +public: + + /******************************************************************************* + ** + ** Function: AidBuffer + ** + ** Description: Parse a string of hex numbers. Store result in an array of + ** bytes. + ** aid: string of hex numbers. + ** + ** Returns: None. + ** + *******************************************************************************/ + AidBuffer (std::string& aid); + + + /******************************************************************************* + ** + ** Function: ~AidBuffer + ** + ** Description: Release all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~AidBuffer (); + + + UINT8* buffer () {return mBuffer;}; + int length () {return mBufferLen;}; + +private: + UINT8* mBuffer; + UINT32 mBufferLen; +}; + + +/*****************************************************************************/ +/*****************************************************************************/ + + +/***************************************************************************** +** +** Name: RouteDataSet +** +** Description: Import and export general routing data using a XML file. +** See /data/bcmnfc/param/route.xml +** +*****************************************************************************/ +class RouteDataSet +{ +public: + typedef std::vector Database; + enum DatabaseSelection {DefaultRouteDatabase, SecElemRouteDatabase}; + + + /******************************************************************************* + ** + ** Function: ~RouteDataSet + ** + ** Description: Release all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~RouteDataSet (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize resources. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool initialize (); + + + /******************************************************************************* + ** + ** Function: import + ** + ** Description: Import data from an XML file. Fill the database. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool import (); + + + /******************************************************************************* + ** + ** Function: getDatabase + ** + ** Description: Obtain a database of routing data. + ** selection: which database. + ** + ** Returns: Pointer to database. + ** + *******************************************************************************/ + Database* getDatabase (DatabaseSelection selection); + + + /******************************************************************************* + ** + ** Function: saveToFile + ** + ** Description: Save XML data from a string into a file. + ** routesXml: XML that represents routes. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + static bool saveToFile (const char* routesXml); + + + /******************************************************************************* + ** + ** Function: loadFromFile + ** + ** Description: Load XML data from file into a string. + ** routesXml: string to receive XML data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + static bool loadFromFile (std::string& routesXml); + + + /******************************************************************************* + ** + ** Function: deleteFile + ** + ** Description: Delete route data XML file. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + static bool deleteFile (); + + /******************************************************************************* + ** + ** Function: printDiagnostic + ** + ** Description: Print some diagnostic output. + ** + ** Returns: None. + ** + *******************************************************************************/ + void printDiagnostic (); + +private: + Database mSecElemRouteDatabase; //routes when NFC service selects sec elem + Database mDefaultRouteDatabase; //routes when NFC service deselects sec elem + static const char* sConfigFile; + static const bool sDebug = false; + + + /******************************************************************************* + ** + ** Function: deleteDatabase + ** + ** Description: Delete all routes stored in all databases. + ** + ** Returns: None. + ** + *******************************************************************************/ + void deleteDatabase (); + + + /******************************************************************************* + ** + ** Function: importProtocolRoute + ** + ** Description: Parse data for protocol routes. + ** element: XML node for one protocol route. + ** database: store data in this database. + ** + ** Returns: None. + ** + *******************************************************************************/ + void importProtocolRoute (xmlNodePtr& element, Database& database); + + + /******************************************************************************* + ** + ** Function: importTechnologyRoute + ** + ** Description: Parse data for technology routes. + ** element: XML node for one technology route. + ** database: store data in this database. + ** + ** Returns: None. + ** + *******************************************************************************/ + void importTechnologyRoute (xmlNodePtr& element, Database& database); +}; + diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp new file mode 100755 index 0000000..f518650 --- /dev/null +++ b/nci/jni/SecureElement.cpp @@ -0,0 +1,1987 @@ +/***************************************************************************** +** +** Name: SecureElement.cpp +** +** Description: Communicate with secure elements that are attached +** to the NFC controller. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include +#include +#include "SecureElement.h" +#include "config.h" +#include "PowerSwitch.h" +#include "HostAidRouter.h" +#include "nfa_vs_brcm_api.h" + + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyTransactionListeners; + extern jmethodID gCachedNfcManagerNotifySeFieldActivated; + extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated; +} + + +/***************************************************************************** +** +** public variables +** +*****************************************************************************/ +int gSEId = -1; // secure element ID to use in connectEE(), -1 means not set +int gGatePipe = -1; // gate id or static pipe id to use in connectEE(), -1 means not set +bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if false, use as gate id + + +////////////////////////////////////////////// +////////////////////////////////////////////// + + +SecureElement SecureElement::sSecElem; + + +/******************************************************************************* +** +** Function: SecureElement +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +SecureElement::SecureElement () +: mActiveEeHandle (NFA_HANDLE_INVALID), + mDestinationGate (4), //loopback gate + mNfaHciHandle (NFA_HANDLE_INVALID), + mNativeData (NULL), + mIsInit (false), + mActualNumEe (0), + mNumEePresent(0), + mbNewEE (true), // by default we start w/thinking there are new EE + mNewPipeId (0), + mNewSourceGate (0), + mActiveSeOverride(0), + mCommandStatus (NFA_STATUS_OK), + mIsPiping (false), + mCurrentRouteSelection (NoRoute), + mTransDataSize(0) +{ + memset (&mEeInfo, 0, sizeof(mEeInfo)); + memset (&mUiccInfo, 0, sizeof(mUiccInfo)); + memset (&mHciCfg, 0, sizeof(mHciCfg)); + memset (mTransData, 0, MAX_TRANS_RECV_SIZE); +} + + +/******************************************************************************* +** +** Function: ~SecureElement +** +** Description: Release all resources. +** +** Returns: None +** +*******************************************************************************/ +SecureElement::~SecureElement () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the SecureElement singleton object. +** +** Returns: SecureElement object. +** +*******************************************************************************/ +SecureElement& SecureElement::getInstance() +{ + return sSecElem; +} + + +/******************************************************************************* +** +** Function: setActiveSeOverride +** +** Description: Specify which secure element to turn on. +** activeSeOverride: ID of secure element +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::setActiveSeOverride(UINT8 activeSeOverride) +{ + ALOGD ("SecureElement::setActiveSeOverride, seid=0x%X", activeSeOverride); + mActiveSeOverride = activeSeOverride; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize all member variables. +** native: Native data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::initialize (nfc_jni_native_data* native) +{ + static const char fn [] = "SecureElement::initialize"; + tNFA_STATUS nfaStat; + UINT8 xx = 0, yy = 0; + unsigned long num = 0; + + ALOGD ("%s: enter", fn); + + if (GetNumValue("NFA_HCI_DEFAULT_DEST_GATE", &num, sizeof(num))) + mDestinationGate = num; + ALOGD ("%s: Default destination gate: %d", __FUNCTION__, mDestinationGate); + + // active SE, if not set active all SEs + if (GetNumValue("ACTIVE_SE", &num, sizeof(num))) + mActiveSeOverride = num; + ALOGD ("%s: Active SE override: %d", __FUNCTION__, mActiveSeOverride); + + mActiveEeHandle = NFA_HANDLE_INVALID; + mNfaHciHandle = NFA_HANDLE_INVALID; + + mNativeData = native; + mActualNumEe = MAX_NUM_EE; + mbNewEE = true; + mNewPipeId = 0; + mNewSourceGate = 0; + mCurrentRouteSelection = NoRoute; + memset (mEeInfo, 0, sizeof(mEeInfo)); + memset (&mUiccInfo, 0, sizeof(mUiccInfo)); + memset (&mHciCfg, 0, sizeof(mHciCfg)); + mUsedAids.clear (); + + // Get Fresh EE info. + if (! getEeInfo()) + return (false); + + { + SyncEventGuard guard (mEeRegisterEvent); + ALOGD ("%s: try ee register", fn); + nfaStat = NFA_EeRegister (nfaEeCallback); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail ee register; error=0x%X", fn, nfaStat); + return (false); + } + mEeRegisterEvent.wait (); + } + + // If the controller has an HCI Network, register for that + for (xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface > 0) && (mEeInfo[xx].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + { + ALOGD ("%s: Found HCI network, try hci register", fn); + + SyncEventGuard guard (mHciRegisterEvent); + + nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE, MAX_TRANS_RECV_SIZE, mHciBufferForStack); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); + return (false); + } + mHciRegisterEvent.wait(); + break; + } + } + + mRouteDataSet.initialize (); + mRouteDataSet.import (); //read XML file + HostAidRouter::getInstance().initialize (); + + mIsInit = true; + ALOGD ("%s: exit", fn); + return (true); +} + + +/******************************************************************************* +** +** Function: finalize +** +** Description: Release all resources. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::finalize () +{ + static const char fn [] = "SecureElement::finalize"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + + NFA_EeDeregister (nfaEeCallback); + + if (mNfaHciHandle != NFA_HANDLE_INVALID) + NFA_HciDeregister ("brcm_jni"); + + mNfaHciHandle = NFA_HANDLE_INVALID; + mNativeData = NULL; + mIsInit = false; + mActualNumEe = 0; + mNumEePresent = 0; + mNewPipeId = 0; + mNewSourceGate = 0; + mIsPiping = false; + memset (mEeInfo, 0, sizeof(mEeInfo)); + memset (&mUiccInfo, 0, sizeof(mUiccInfo)); + + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: getEeInfo +** +** Description: Get latest information about execution environments from stack. +** +** Returns: True if at least 1 EE is available. +** +*******************************************************************************/ +bool SecureElement::getEeInfo() +{ + static const char fn [] = "SecureElement::getEeInfo"; + ALOGD ("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + UINT8 xx = 0, yy = 0; + + // If mbNewEE is true then there is new EE info. + if (mbNewEE) + { + mActualNumEe = MAX_NUM_EE; + + if ((nfaStat = NFA_EeGetInfo (&mActualNumEe, mEeInfo)) != NFA_STATUS_OK) + { + ALOGE ("%s: fail get info; error=0x%X", fn, nfaStat); + mActualNumEe = 0; + } + else + { + mbNewEE = false; + + ALOGD ("%s: num EEs discovered: %u", fn, mActualNumEe); + if (mActualNumEe != 0) + { + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + mNumEePresent++; + + ALOGD ("%s: EE[%u] Handle: 0x%04x Status: %s Num I/f: %u: (0x%02x, 0x%02x) Num TLVs: %u", + fn, xx, mEeInfo[xx].ee_handle, eeStatusToString(mEeInfo[xx].ee_status), mEeInfo[xx].num_interface, + mEeInfo[xx].ee_interface[0], mEeInfo[xx].ee_interface[1], mEeInfo[xx].num_tlvs); + + for (yy = 0; yy < mEeInfo[xx].num_tlvs; yy++) + { + ALOGD ("%s: EE[%u] TLV[%u] Tag: 0x%02x Len: %u Values[]: 0x%02x 0x%02x 0x%02x ...", + fn, xx, yy, mEeInfo[xx].ee_tlv[yy].tag, mEeInfo[xx].ee_tlv[yy].len, mEeInfo[xx].ee_tlv[yy].info[0], + mEeInfo[xx].ee_tlv[yy].info[1], mEeInfo[xx].ee_tlv[yy].info[2]); + } + } + } + } + } + ALOGD ("%s: exit; mActualNumEe=%d, mNumEePresent=%d", fn, mActualNumEe,mNumEePresent); + return (mActualNumEe != 0); +} + + +/******************************************************************************* +** +** Function: getListOfEeHandles +** +** Description: Get the list of handles of all execution environments. +** e: Java Virtual Machine. +** +** Returns: List of handles of all execution environments. +** +*******************************************************************************/ +jintArray SecureElement::getListOfEeHandles (JNIEnv* e) +{ + static const char fn [] = "SecureElement::getListOfEeHandles"; + ALOGD ("%s: enter", fn); + if (mNumEePresent == 0) + return NULL; + jintArray list = NULL; + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + return (NULL); + } + + // Get Fresh EE info. + if (! getEeInfo()) + return (NULL); + + list = e->NewIntArray (mNumEePresent); //allocate array + jint jj = 0; + int cnt = 0; + for (int ii = 0; ii < mActualNumEe && cnt < mNumEePresent; ii++) + { + ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle); + if ((mEeInfo[ii].num_interface == 0) || (mEeInfo[ii].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + { + continue; + } + + jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE; + e->SetIntArrayRegion (list, cnt++, 1, &jj); + } + //e->DeleteLocalRef (list); + + ALOGD("%s: exit", fn); + return list; +} + + +/******************************************************************************* +** +** Function: activate +** +** Description: Turn on the secure element. +** seID: ID of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::activate (jint seID) +{ + static const char fn [] = "SecureElement::activate"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + int numActivatedEe = 0; + + ALOGD ("%s: enter; seID=0x%X", fn, seID); + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + return false; + } + + if (mActiveEeHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: already active", fn); + return true; + } + + // Get Fresh EE info if needed. + if (! getEeInfo()) + { + ALOGE ("%s: no EE info", fn); + return false; + } + + mActiveEeHandle = getDefaultEeHandle(); + ALOGD ("%s: active ee h=0x%X, override se=0x%X", fn, mActiveEeHandle, mActiveSeOverride); + if (mActiveEeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: ee not found", fn); + return false; + } + + UINT16 override_se = 0; + if (mActiveSeOverride) + override_se = NFA_HANDLE_GROUP_EE | mActiveSeOverride; + + ALOGD ("%s: override seid=0x%X", fn, override_se ); + //activate every discovered secure element + for (int index=0; index < mActualNumEe; index++) + { + tNFA_EE_INFO& eeItem = mEeInfo[index]; + + if ((eeItem.ee_handle == EE_HANDLE_0xF3) || (eeItem.ee_handle == EE_HANDLE_0xF4)) + { + if (override_se && (override_se != eeItem.ee_handle) ) + continue; // do not enable all SEs; only the override one + + if (eeItem.ee_status != NFC_NFCEE_STATUS_INACTIVE) + { + ALOGD ("%s: h=0x%X already activated", fn, eeItem.ee_handle); + numActivatedEe++; + continue; + } + + { + SyncEventGuard guard (mEeSetModeEvent); + ALOGD ("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle); + if ((nfaStat = NFA_EeModeSet (eeItem.ee_handle, NFA_EE_MD_ACTIVATE)) == NFA_STATUS_OK) + { + mEeSetModeEvent.wait (); //wait for NFA_EE_MODE_SET_EVT + if (eeItem.ee_status == NFC_NFCEE_STATUS_ACTIVE) + numActivatedEe++; + } + else + ALOGE ("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat); + } + } + } //for + + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[xx].ee_status != NFC_NFCEE_STATUS_INACTIVE)) + { + mActiveEeHandle = mEeInfo[xx].ee_handle; + break; + } + } + + ALOGD ("%s: exit; ok=%u", fn, numActivatedEe > 0); + return numActivatedEe > 0; +} + + +/******************************************************************************* +** +** Function: deactivate +** +** Description: Turn off the secure element. +** seID: ID of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::deactivate (jint seID) +{ + static const char fn [] = "SecureElement::deactivate"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + int numDeactivatedEe = 0; + bool retval = false; + + ALOGD ("%s: enter; seID=0x%X, mActiveEeHandle=0x%X", fn, seID, mActiveEeHandle); + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + goto TheEnd; + } + + //if the controller is routing to sec elems or piping, + //then the secure element cannot be deactivated + if ((mCurrentRouteSelection == SecElemRoute) || mIsPiping) + { + ALOGE ("%s: still busy", fn); + goto TheEnd; + } + + if (mActiveEeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid EE handle", fn); + goto TheEnd; + } + + mActiveEeHandle = NFA_HANDLE_INVALID; + retval = true; + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: notifyTransactionListenersOfAid +** +** Description: Notify the NFC service about a transaction event from secure element. +** aid: Buffer contains application ID. +** aidLen: Length of application ID. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::notifyTransactionListenersOfAid (const UINT8* aidBuffer, UINT8 aidBufferLen) +{ + static const char fn [] = "SecureElement::notifyTransactionListenersOfAid"; + ALOGD ("%s: enter; aid len=%u", fn, aidBufferLen); + + if (aidBufferLen == 0) + return; + + jobject tlvJavaArray = NULL; + JNIEnv* e = NULL; + UINT8* tlv = 0; + const UINT16 tlvMaxLen = aidBufferLen + 10; + UINT16 tlvActualLen = 0; + bool stat = false; + + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + tlv = new UINT8 [tlvMaxLen]; + if (tlv == NULL) + { + ALOGE ("%s: fail allocate tlv", fn); + goto TheEnd; + } + + memcpy (tlv, aidBuffer, aidBufferLen); + tlvActualLen = aidBufferLen; + + tlvJavaArray = e->NewByteArray (tlvActualLen); + if (tlvJavaArray == NULL) + { + ALOGE ("%s: fail allocate array", fn); + goto TheEnd; + } + + e->SetByteArrayRegion ((jbyteArray)tlvJavaArray, 0, tlvActualLen, (jbyte *)tlv); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail fill array", fn); + goto TheEnd; + } + + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + goto TheEnd; + } + +TheEnd: + if (tlvJavaArray) + e->DeleteLocalRef (tlvJavaArray); + mNativeData->vm->DetachCurrentThread (); + delete [] tlv; + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: connectEE +** +** Description: Connect to the execution environment. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::connectEE () +{ + static const char fn [] = "SecureElement::connectEE"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retVal = false; + UINT8 destHost = 0; + unsigned long num = 0; + char pipeConfName[40]; + tNFA_HANDLE eeHandle = mActiveEeHandle; + + ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d", + fn, mActiveEeHandle, gSEId, gGatePipe, gUseStaticPipe); + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + return (false); + } + + if (gSEId != -1) + { + eeHandle = gSEId | NFA_HANDLE_GROUP_EE; + ALOGD ("%s: Using SEID: 0x%x", fn, eeHandle ); + } + + if (eeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid handle 0x%X", fn, eeHandle); + return (false); + } + + tNFA_EE_INFO *pEE = findEeByHandle (eeHandle); + + if (pEE == NULL) + { + ALOGE ("%s: Handle 0x%04x NOT FOUND !!", fn, eeHandle); + return (false); + } + + mNewSourceGate = 0; + + if (gGatePipe == -1) + { + // pipe/gate num was not specifed by app, get from config file + mNewPipeId = 0; + + // Construct the PIPE name based on the EE handle (e.g. NFA_HCI_STATIC_PIPE_ID_F3 for UICC0). + snprintf (pipeConfName, sizeof(pipeConfName), "NFA_HCI_STATIC_PIPE_ID_%02X", eeHandle & NFA_HANDLE_MASK); + + if (GetNumValue(pipeConfName, &num, sizeof(num)) && (num != 0)) + { + mNewPipeId = num; + ALOGD ("%s: Using static pipe id: 0x%X", __FUNCTION__, mNewPipeId); + } + else + { + ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName); + } + } + else + { + if (gUseStaticPipe) + { + mNewPipeId = gGatePipe; + } + else + { + mNewPipeId = 0; + mDestinationGate= gGatePipe; + } + } + + // If the .conf file had a static pipe to use, just use it. + if (mNewPipeId != 0) + { + nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, mNewPipeId); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail create static pipe; error=0x%X", fn, nfaStat); + retVal = false; + goto TheEnd; + } + } + else + { + if ( (pEE->num_tlvs >= 1) && (pEE->ee_tlv[0].tag == NFA_EE_TAG_HCI_HOST_ID) ) + destHost = pEE->ee_tlv[0].info[0]; + else + destHost = 2; + + // Get a list of existing gates and pipes + { + ALOGD ("%s: get gate, pipe list", fn); + SyncEventGuard guard (mPipeListEvent); + nfaStat = NFA_HciGetGateAndPipeList (mNfaHciHandle); + if (nfaStat == NFA_STATUS_OK) + { + mPipeListEvent.wait(); + if (mHciCfg.status == NFA_STATUS_OK) + { + for (UINT8 xx = 0; xx < mHciCfg.num_pipes; xx++) + { + if ( (mHciCfg.pipe[xx].dest_host == destHost) + && (mHciCfg.pipe[xx].dest_gate == mDestinationGate) ) + { + mNewSourceGate = mHciCfg.pipe[xx].local_gate; + mNewPipeId = mHciCfg.pipe[xx].pipe_id; + + ALOGD ("%s: found configured gate: 0x%02x pipe: 0x%02x", fn, mNewSourceGate, mNewPipeId); + break; + } + } + } + } + } + + if (mNewSourceGate == 0) + { + ALOGD ("%s: allocate gate", fn); + //allocate a source gate and store in mNewSourceGate + SyncEventGuard guard (mAllocateGateEvent); + if ((nfaStat = NFA_HciAllocGate (mNfaHciHandle)) != NFA_STATUS_OK) + { + ALOGE ("%s: fail allocate source gate; error=0x%X", fn, nfaStat); + goto TheEnd; + } + mAllocateGateEvent.wait (); + if (mCommandStatus != NFA_STATUS_OK) + goto TheEnd; + } + + if (mNewPipeId == 0) + { + ALOGD ("%s: create pipe", fn); + SyncEventGuard guard (mCreatePipeEvent); + nfaStat = NFA_HciCreatePipe (mNfaHciHandle, mNewSourceGate, destHost, mDestinationGate); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail create pipe; error=0x%X", fn, nfaStat); + goto TheEnd; + } + mCreatePipeEvent.wait (); + if (mCommandStatus != NFA_STATUS_OK) + goto TheEnd; + } + + { + ALOGD ("%s: open pipe", fn); + SyncEventGuard guard (mPipeOpenedEvent); + nfaStat = NFA_HciOpenPipe (mNfaHciHandle, mNewPipeId); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail open pipe; error=0x%X", fn, nfaStat); + goto TheEnd; + } + mPipeOpenedEvent.wait (); + if (mCommandStatus != NFA_STATUS_OK) + goto TheEnd; + } + } + + retVal = true; + +TheEnd: + mIsPiping = retVal; + if (!retVal) + { + // if open failed we need to de-allocate the gate + disconnectEE(0); + } + + ALOGD ("%s: exit; ok=%u", fn, retVal); + return retVal; +} + + +/******************************************************************************* +** +** Function: disconnectEE +** +** Description: Disconnect from the execution environment. +** seID: ID of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::disconnectEE (jint seID) +{ + static const char fn [] = "SecureElement::disconnectEE"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + tNFA_HANDLE eeHandle = seID; + + ALOGD("%s: seID=0x%X; handle=0x%04x", fn, seID, eeHandle); + + if (mNewSourceGate) + { + SyncEventGuard guard (mDeallocateGateEvent); + if ((nfaStat = NFA_HciDeallocGate (mNfaHciHandle, mNewSourceGate)) == NFA_STATUS_OK) + mDeallocateGateEvent.wait (); + else + ALOGE ("%s: fail dealloc gate; error=0x%X", fn, nfaStat); + } + mIsPiping = false; + return true; +} + + +/******************************************************************************* +** +** Function: transceive +** +** Description: Send data to the secure element; read it's response. +** xmitBuffer: Data to transmit. +** xmitBufferSize: Length of data. +** recvBuffer: Buffer to receive response. +** recvBufferMaxSize: Maximum size of buffer. +** recvBufferActualSize: Actual length of response. +** timeoutMillisec: timeout in millisecond. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer, + INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec) +{ + static const char fn [] = "SecureElement::transceive"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool isSuccess = false; + bool waitOk = false; + + ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%d", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); + + { + SyncEventGuard guard (mTransceiveEvent); + mTransDataSize = 0; + if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71)) + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer); + else + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer); + + if (nfaStat == NFA_STATUS_OK) + { + waitOk = mTransceiveEvent.wait (timeoutMillisec); + if (waitOk == false) //timeout occurs + { + ALOGE ("%s: wait response timeout", fn); + goto TheEnd; + } + } + else + { + ALOGE ("%s: fail send data; error=0x%X", fn, nfaStat); + goto TheEnd; + } + } + + if (mTransDataSize > recvBufferMaxSize) + recvBufferActualSize = recvBufferMaxSize; + else + recvBufferActualSize = mTransDataSize; + + memcpy(recvBuffer, mTransData, recvBufferActualSize); + isSuccess = true; + +TheEnd: + ALOGD ("%s: exit; isSuccess: %d; recvBufferActualSize: %ld", fn, isSuccess, recvBufferActualSize); + return (isSuccess); +} + + +/******************************************************************************* +** +** Function: notifyRfFieldEvent +** +** Description: Notify the NFC service about RF field events from the stack. +** isActive: Whether any secure element is activated. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::notifyRfFieldEvent (bool isActive) +{ + static const char fn [] = "SecureElement::notifyRfFieldEvent"; + JNIEnv *e = NULL; + + ALOGD ("%s: enter; is active=%u", fn, isActive); + mNativeData->vm->AttachCurrentThread (&e, NULL); + + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + if (isActive) + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldActivated); + else + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldDeactivated); + + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: storeUiccInfo +** +** Description: Store a copy of the execution environment information from the stack. +** info: execution environment information. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info) +{ + static const char fn [] = "SecureElement::storeUiccInfo"; + ALOGD ("%s: Status: %u Num EE: %u", fn, info.status, info.num_ee); + + SyncEventGuard guard (mUiccInfoEvent); + memcpy (&mUiccInfo, &info, sizeof(mUiccInfo)); + for (UINT8 xx = 0; xx < info.num_ee; xx++) + { + //for each technology (A, B, F, B'), print the bit field that shows + //what protocol(s) is support by that technology + ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x", + fn, xx, info.ee_disc_info[xx].ee_handle, + info.ee_disc_info[xx].la_protocol, + info.ee_disc_info[xx].lb_protocol, + info.ee_disc_info[xx].lf_protocol, + info.ee_disc_info[xx].lbp_protocol); + } + mUiccInfoEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: getUiccId +** +** Description: Get the ID of the secure element. +** eeHandle: Handle to the secure element. +** uid: Array to receive the ID. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid) +{ + static const char fn [] = "SecureElement::getUiccId"; + ALOGD ("%s: ee h=0x%X", fn, eeHandle); + bool retval = false; + JNIEnv* e = NULL; + + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return false; + } + + findUiccByHandle (eeHandle); + //cannot get UID from the stack; nothing to do + +TheEnd: + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit; ret=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: getTechnologyList +** +** Description: Get all the technologies supported by a secure element. +** eeHandle: Handle of secure element. +** techList: List to receive the technologies. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList) +{ + static const char fn [] = "SecureElement::getTechnologyList"; + ALOGD ("%s: ee h=0x%X", fn, eeHandle); + bool retval = false; + JNIEnv* e = NULL; + jint theList = 0; + + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return false; + } + + tNFA_EE_DISCOVER_INFO *pUICC = findUiccByHandle (eeHandle); + + if (pUICC->la_protocol != 0) + theList = TARGET_TYPE_ISO14443_3A; + else if (pUICC->lb_protocol != 0) + theList = TARGET_TYPE_ISO14443_3B; + else if (pUICC->lf_protocol != 0) + theList = TARGET_TYPE_FELICA; + else if (pUICC->lbp_protocol != 0) + theList = TARGET_TYPE_ISO14443_3B; + else + theList = TARGET_TYPE_UNKNOWN; + +TheEnd: + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit; ret=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: adjustRoutes +** +** Description: Adjust routes in the controller's listen-mode routing table. +** selection: which set of routes to configure the controller. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::adjustRoutes (RouteSelection selection) +{ + static const char fn [] = "SecureElement::adjustRoutes"; + ALOGD ("%s: enter; selection=%u", fn, selection); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + RouteDataSet::Database* db = mRouteDataSet.getDatabase (RouteDataSet::DefaultRouteDatabase); + + if (selection == SecElemRoute) + db = mRouteDataSet.getDatabase (RouteDataSet::SecElemRouteDatabase); + + mCurrentRouteSelection = selection; + adjustProtocolRoutes (db, selection); + adjustTechnologyRoutes (db, selection); + HostAidRouter::getInstance ().deleteAllRoutes (); //stop all AID routes to host + + if (db->empty()) + { + if (selection == DefaultRoute) + HostAidRouter::getInstance ().addPpseRoute (); + ALOGD ("%s: no route configuration", fn); + goto TheEnd; + } + + +TheEnd: + NFA_EeUpdateNow (); //apply new routes now + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: applyRoutes +** +** Description: Read route data from file and apply them again. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::applyRoutes () +{ + static const char fn [] = "SecureElement::applyRoutes"; + ALOGD ("%s: enter", fn); + if (mCurrentRouteSelection != NoRoute) + { + mRouteDataSet.import (); //read XML file + adjustRoutes (mCurrentRouteSelection); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: adjustProtocolRoutes +** +** Description: Adjust default routing based on protocol in NFC listen mode. +** isRouteToEe: Whether routing to EE (true) or host (false). +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection) +{ + static const char fn [] = "SecureElement::adjustProtocolRoutes"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + const tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_ISO_DEP; + + /////////////////////// + // delete route to host + /////////////////////// + { + ALOGD ("%s: delete route to host", fn); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat); + } + + /////////////////////// + // delete route to every sec elem + /////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // configure route for every discovered sec elem + ////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + //if sec elem is active + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power + tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off + tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power + + //for every route in XML, look for protocol route; + //collect every protocol according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForProtocol* route = NULL; + if (routeData->mRouteType != RouteData::ProtocolRoute) + continue; //skip other kinds of routing data + route = (RouteDataForProtocol*) (*iter); + if (route->mNfaEeHandle == mEeInfo[i].ee_handle) + { + if (route->mSwitchOn) + protocolsSwitchOn |= route->mProtocol; + if (route->mSwitchOff) + protocolsSwitchOff |= route->mProtocol; + if (route->mBatteryOff) + protocolsBatteryOff |= route->mProtocol; + } + } + + if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle, + protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } //if sec elem is active + } //for every discovered sec elem + + ////////////////////// + // configure route to host + ////////////////////// + { + tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power + tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off + tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power + + //for every route in XML, look for protocol route; + //collect every protocol according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForProtocol* route = NULL; + if (routeData->mRouteType != RouteData::ProtocolRoute) + continue; //skip other kinds of routing data + route = (RouteDataForProtocol*) (*iter); + if (route->mNfaEeHandle == NFA_EE_HANDLE_DH) + { + if (route->mSwitchOn) + protocolsSwitchOn |= route->mProtocol; + if (route->mSwitchOff) + protocolsSwitchOff |= route->mProtocol; + if (route->mBatteryOff) + protocolsBatteryOff |= route->mProtocol; + } + } + + if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH, + protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // if route database is empty, setup a default route + ////////////////////// + if (db->empty()) + { + tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH; + if (routeSelection == SecElemRoute) + eeHandle = getDefaultEeHandle (); + ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultProtoRouting (eeHandle, protoMask, 0, 0); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: adjustTechnologyRoutes +** +** Description: Adjust default routing based on technology in NFC listen mode. +** isRouteToEe: Whether routing to EE (true) or host (false). +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection) +{ + static const char fn [] = "SecureElement::adjustTechnologyRoutes"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + const tNFA_TECHNOLOGY_MASK techMask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B; + + /////////////////////// + // delete route to host + /////////////////////// + { + ALOGD ("%s: delete route to host", fn); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat); + } + + /////////////////////// + // delete route to every sec elem + /////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // configure route for every discovered sec elem + ////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + //if sec elem is active + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power + tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off + tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power + + //for every route in XML, look for tech route; + //collect every tech according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForTechnology* route = NULL; + if (routeData->mRouteType != RouteData::TechnologyRoute) + continue; //skip other kinds of routing data + route = (RouteDataForTechnology*) (*iter); + if (route->mNfaEeHandle == mEeInfo[i].ee_handle) + { + if (route->mSwitchOn) + techsSwitchOn |= route->mTechnology; + if (route->mSwitchOff) + techsSwitchOff |= route->mTechnology; + if (route->mBatteryOff) + techsBatteryOff |= route->mTechnology; + } + } + + if (techsSwitchOn | techsSwitchOff | techsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle, + techsSwitchOn, techsSwitchOff, techsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } //if sec elem is active + } //for every discovered sec elem + + ////////////////////// + // configure route to host + ////////////////////// + { + tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power + tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off + tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power + + //for every route in XML, look for protocol route; + //collect every protocol according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForTechnology * route = NULL; + if (routeData->mRouteType != RouteData::TechnologyRoute) + continue; //skip other kinds of routing data + route = (RouteDataForTechnology*) (*iter); + if (route->mNfaEeHandle == NFA_EE_HANDLE_DH) + { + if (route->mSwitchOn) + techsSwitchOn |= route->mTechnology; + if (route->mSwitchOff) + techsSwitchOff |= route->mTechnology; + if (route->mBatteryOff) + techsBatteryOff |= route->mTechnology; + } + } + + if (techsSwitchOn | techsSwitchOff | techsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH, + techsSwitchOn, techsSwitchOff, techsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // if route database is empty, setup a default route + ////////////////////// + if (db->empty()) + { + tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH; + if (routeSelection == SecElemRoute) + eeHandle = getDefaultEeHandle (); + ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultTechRouting (eeHandle, techMask, 0, 0); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaEeCallback +** +** Description: Receive execution environment-related events from stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData) +{ + static const char fn [] = "SecureElement::nfaEeCallback"; + + switch (event) + { + case NFA_EE_REGISTER_EVT: + { + SyncEventGuard guard (sSecElem.mEeRegisterEvent); + ALOGD ("%s: NFA_EE_REGISTER_EVT; status=%u", fn, eventData->ee_register); + sSecElem.mEeRegisterEvent.notifyOne(); + } + break; + + case NFA_EE_MODE_SET_EVT: + { + ALOGD ("%s: NFA_EE_MODE_SET_EVT; status: 0x%04X handle: 0x%04X mActiveEeHandle: 0x%04X", fn, + eventData->mode_set.status, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle); + + if (eventData->mode_set.status == NFA_STATUS_OK) + { + tNFA_EE_INFO *pEE = sSecElem.findEeByHandle (eventData->mode_set.ee_handle); + if (pEE) + { + pEE->ee_status ^= 1; + ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status); + } + else + ALOGE ("%s: NFA_EE_MODE_SET_EVT; EE: 0x%04x not found. mActiveEeHandle: 0x%04x", fn, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle); + } + SyncEventGuard guard (sSecElem.mEeSetModeEvent); + sSecElem.mEeSetModeEvent.notifyOne(); + } + break; + + case NFA_EE_SET_TECH_CFG_EVT: + { + ALOGD ("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, eventData->status); + SyncEventGuard guard (sSecElem.mRoutingEvent); + sSecElem.mRoutingEvent.notifyOne (); + } + break; + + case NFA_EE_SET_PROTO_CFG_EVT: + { + ALOGD ("%s: NFA_EE_SET_PROTO_CFG_EVT; status=0x%X", fn, eventData->status); + SyncEventGuard guard (sSecElem.mRoutingEvent); + sSecElem.mRoutingEvent.notifyOne (); + } + break; + + case NFA_EE_ACTION_EVT: + { + tNFA_EE_ACTION& action = eventData->action; + if (action.trigger == NFC_EE_TRIG_SELECT) + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=select (0x%X)", fn, action.ee_handle, action.trigger); + else if (action.trigger == NFC_EE_TRIG_APP_INIT) + { + tNFC_APP_INIT& app_init = action.param.app_init; + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=app-init (0x%X); aid len=%u; data len=%u", fn, + action.ee_handle, action.trigger, app_init.len_aid, app_init.len_data); + //if app-init operation is successful; + //app_init.data[] contains two bytes, which are the status codes of the event; + //app_init.data[] does not contain an APDU response; + //see EMV Contactless Specification for Payment Systems; Book B; Entry Point Specification; + //version 2.1; March 2011; section 3.3.3.5; + if ( (app_init.len_data > 1) && + (app_init.data[0] == 0x90) && + (app_init.data[1] == 0x00) ) + { + sSecElem.notifyTransactionListenersOfAid (app_init.aid, app_init.len_aid); + } + } + else if (action.trigger == NFC_EE_TRIG_RF_PROTOCOL) + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf protocol (0x%X)", fn, action.ee_handle, action.trigger); + else if (action.trigger == NFC_EE_TRIG_RF_TECHNOLOGY) + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf tech (0x%X)", fn, action.ee_handle, action.trigger); + else + ALOGE ("%s: NFA_EE_ACTION_EVT; h=0x%X; unknown trigger (0x%X)", fn, action.ee_handle, action.trigger); + } + break; + + case NFA_EE_DISCOVER_REQ_EVT: + ALOGD ("%s: NFA_EE_DISCOVER_REQ_EVT; status=0x%X; num ee=%u", __FUNCTION__, + eventData->discover_req.status, eventData->discover_req.num_ee); + sSecElem.storeUiccInfo (eventData->discover_req); + break; + + case NFA_EE_NO_CB_ERR_EVT: + ALOGD ("%s: NFA_EE_NO_CB_ERR_EVT status=%u", fn, eventData->status); + break; + + case NFA_EE_ADD_AID_EVT: + { + ALOGD ("%s: NFA_EE_ADD_AID_EVT status=%u", fn, eventData->status); + SyncEventGuard guard (sSecElem.mAidAddRemoveEvent); + sSecElem.mAidAddRemoveEvent.notifyOne (); + } + break; + + case NFA_EE_REMOVE_AID_EVT: + { + ALOGD ("%s: NFA_EE_REMOVE_AID_EVT status=%u", fn, eventData->status); + SyncEventGuard guard (sSecElem.mAidAddRemoveEvent); + sSecElem.mAidAddRemoveEvent.notifyOne (); + } + break; + + case NFA_EE_NEW_EE_EVT: + { + ALOGD ("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn, + eventData->new_ee.ee_handle, eventData->new_ee.ee_status); + // Indicate there are new EE + sSecElem.mbNewEE = true; + } + break; + + default: + ALOGE ("%s: unknown event=%u ????", fn, event); + break; + } +} + +/******************************************************************************* +** +** Function getSeVerInfo +** +** Description Gets version information and id for a secure element. The +** seIndex parmeter is the zero based index of the secure +** element to get verion info for. The version infommation +** is returned as a string int the verInfo parameter. +** +** Returns ture on success, false on failure +** +*******************************************************************************/ +bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid) +{ + ALOGD("%s: enter, seIndex=%d", __FUNCTION__, seIndex); + + if (seIndex > (mActualNumEe-1)) + { + ALOGE("%s: invalid se index: %d, only %d SEs in system", __FUNCTION__, seIndex, mActualNumEe); + return false; + } + + *seid = mEeInfo[seIndex].ee_handle; + + if ((mEeInfo[seIndex].num_interface == 0) || (mEeInfo[seIndex].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + { + return false; + } + + strncpy(verInfo, "Version info not available", verInfoSz-1); + verInfo[verInfoSz-1] = '\0'; + + UINT8 pipe = (mEeInfo[seIndex].ee_handle == EE_HANDLE_0xF3) ? 0x70 : 0x71; + + tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, pipe); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_HciAddStaticPipe() failed, pipe = 0x%x, error=0x%X", __FUNCTION__, pipe, nfaStat); + return true; + } + + SyncEventGuard guard (mVerInfoEvent); + if (NFA_STATUS_OK == (nfaStat = NFA_HciGetRegistry (mNfaHciHandle, pipe, 0x02))) + { + if (false == mVerInfoEvent.wait(200)) + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + } + else + { + snprintf(verInfo, verInfoSz-1, "Oberthur OS S/N: 0x%02x%02x%02x", mVerInfo[0], mVerInfo[1], mVerInfo[2]); + verInfo[verInfoSz-1] = '\0'; + } + } + else + { + ALOGE ("%s: NFA_HciGetRegistry () failed: 0x%X", __FUNCTION__, nfaStat); + } + return true; +} + +/******************************************************************************* +** +** Function getActualNumEe +** +** Description Returns number of secure elements we know about. +** +** Returns Number of secure elements we know about. +** +*******************************************************************************/ +UINT8 SecureElement::getActualNumEe() +{ + return mActualNumEe; +} + +/******************************************************************************* +** +** Function: nfaHciCallback +** +** Description: Receive Host Controller Interface-related events from stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData) +{ + static const char fn [] = "SecureElement::nfaHciCallback"; + ALOGD ("%s: event=0x%X", fn, event); + + switch (event) + { + case NFA_HCI_REGISTER_EVT: + { + ALOGD ("%s: NFA_HCI_REGISTER_EVT; status=0x%X; handle=0x%X", fn, + eventData->hci_register.status, eventData->hci_register.hci_handle); + SyncEventGuard guard (sSecElem.mHciRegisterEvent); + sSecElem.mNfaHciHandle = eventData->hci_register.hci_handle; + sSecElem.mHciRegisterEvent.notifyOne(); + } + break; + + case NFA_HCI_ALLOCATE_GATE_EVT: + { + ALOGD ("%s: NFA_HCI_ALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, eventData->status, eventData->allocated.gate); + SyncEventGuard guard (sSecElem.mAllocateGateEvent); + sSecElem.mCommandStatus = eventData->status; + sSecElem.mNewSourceGate = (eventData->allocated.status == NFA_STATUS_OK) ? eventData->allocated.gate : 0; + sSecElem.mAllocateGateEvent.notifyOne(); + } + break; + + case NFA_HCI_DEALLOCATE_GATE_EVT: + { + tNFA_HCI_DEALLOCATE_GATE& deallocated = eventData->deallocated; + ALOGD ("%s: NFA_HCI_DEALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, deallocated.status, deallocated.gate); + SyncEventGuard guard (sSecElem.mDeallocateGateEvent); + sSecElem.mDeallocateGateEvent.notifyOne(); + } + break; + + case NFA_HCI_GET_GATE_PIPE_LIST_EVT: + { + ALOGD ("%s: NFA_HCI_GET_GATE_PIPE_LIST_EVT; status=0x%X; num_pipes: %u num_gates: %u", fn, + eventData->gates_pipes.status, eventData->gates_pipes.num_pipes, eventData->gates_pipes.num_gates); + SyncEventGuard guard (sSecElem.mPipeListEvent); + sSecElem.mCommandStatus = eventData->gates_pipes.status; + sSecElem.mHciCfg = eventData->gates_pipes; + sSecElem.mPipeListEvent.notifyOne(); + } + break; + + case NFA_HCI_CREATE_PIPE_EVT: + { + ALOGD ("%s: NFA_HCI_CREATE_PIPE_EVT; status=0x%X; pipe=0x%X; src gate=0x%X; dest host=0x%X; dest gate=0x%X", fn, + eventData->created.status, eventData->created.pipe, eventData->created.source_gate, eventData->created.dest_host, eventData->created.dest_gate); + SyncEventGuard guard (sSecElem.mCreatePipeEvent); + sSecElem.mCommandStatus = eventData->created.status; + sSecElem.mNewPipeId = eventData->created.pipe; + sSecElem.mCreatePipeEvent.notifyOne(); + } + break; + + case NFA_HCI_OPEN_PIPE_EVT: + { + ALOGD ("%s: NFA_HCI_OPEN_PIPE_EVT; status=0x%X; pipe=0x%X", fn, eventData->opened.status, eventData->opened.pipe); + SyncEventGuard guard (sSecElem.mPipeOpenedEvent); + sSecElem.mCommandStatus = eventData->opened.status; + sSecElem.mPipeOpenedEvent.notifyOne(); + } + break; + + case NFA_HCI_EVENT_SENT_EVT: + ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status); + break; + + case NFA_HCI_RSP_RCVD_EVT: + ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status:0x%X, pipe=0x%X, rsp_code:0x%X, rsp_len=%u", fn, + eventData->rsp_rcvd.status, eventData->rsp_rcvd.pipe, + eventData->rsp_rcvd.rsp_code, eventData->rsp_rcvd.rsp_len); + break; + + case NFA_HCI_GET_REG_RSP_EVT : + ALOGD ("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn, + eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len); + if (eventData->registry.data_len >= 19 && ((eventData->registry.pipe == STATIC_PIPE_0x70) || (eventData->registry.pipe == STATIC_PIPE_0x71))) + { + // Oberthur OS version is in bytes 16,17, and 18 + sSecElem.mVerInfo[0] = eventData->registry.reg_data[16]; + sSecElem.mVerInfo[1] = eventData->registry.reg_data[17]; + sSecElem.mVerInfo[2] = eventData->registry.reg_data[18]; + SyncEventGuard guard (sSecElem.mVerInfoEvent); + sSecElem.mVerInfoEvent.notifyOne (); + } + break; + + case NFA_HCI_EVENT_RCVD_EVT: + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X", fn, + eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe); + if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71)) + { + //ISO7816 APDU arrived from sec elem's static pipes + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; %u bytes from static pipe", fn, eventData->rcvd_evt.evt_len); + sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; + memcpy (sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); + SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mTransceiveEvent.notifyOne (); + break; + } + switch (eventData->rcvd_evt.evt_code) + { + case NFA_HCI_EVT_POST_DATA: + { + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA; len=%u", fn, eventData->rcvd_evt.evt_len); + sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; + memcpy(sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); + SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mTransceiveEvent.notifyOne (); + } + break; + + case NFA_HCI_EVT_HCI_END_OF_OPERATION: + break; + + case NFA_HCI_EVT_HOT_PLUG: + break; + + case NFA_HCI_EVT_CONNECTIVITY: + break; + + case NFA_HCI_EVT_TRANSACTION: + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn); + // If we got an AID, notify any listeners + if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) ) + sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2], eventData->rcvd_evt.p_evt_buf[1]); + break; + + case NFA_HCI_EVT_OPERATION_ENDED: + break; + + default: + ALOGE ("%s: NFA_HCI_EVENT_RCVD_EVT; unknown event 0x%X ????", fn, eventData->rcvd_evt.evt_code); + break; + } + break; //case NFA_HCI_EVENT_RCVD_EVT + + default: + ALOGE ("%s: unknown event code=0x%X ????", fn, event); + break; + } +} + + +/******************************************************************************* +** +** Function: findEeByHandle +** +** Description: Find information about an execution environment. +** eeHandle: Handle to execution environment. +** +** Returns: Information about an execution environment. +** +*******************************************************************************/ +tNFA_EE_INFO *SecureElement::findEeByHandle (tNFA_HANDLE eeHandle) +{ + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if (mEeInfo[xx].ee_handle == eeHandle) + return (&mEeInfo[xx]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: getDefaultEeHandle +** +** Description: Get the handle to the execution environment. +** +** Returns: Handle to the execution environment. +** +*******************************************************************************/ +tNFA_HANDLE SecureElement::getDefaultEeHandle () +{ + // Find the first EE that is not the HCI Access i/f. + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + return (mEeInfo[xx].ee_handle); + } + return NFA_HANDLE_INVALID; +} + + + /******************************************************************************* + ** + ** Function: findUiccByHandle + ** + ** Description: Find information about an execution environment. + ** eeHandle: Handle of the execution environment. + ** + ** Returns: Information about the execution environment. + ** + *******************************************************************************/ +tNFA_EE_DISCOVER_INFO *SecureElement::findUiccByHandle (tNFA_HANDLE eeHandle) +{ + for (UINT8 index = 0; index < mUiccInfo.num_ee; index++) + { + if (mUiccInfo.ee_disc_info[index].ee_handle == eeHandle) + { + return (&mUiccInfo.ee_disc_info[index]); + } + } + ALOGE ("SecureElement::findUiccByHandle: ee h=0x%4x not found", eeHandle); + return NULL; +} + + +/******************************************************************************* +** +** Function: eeStatusToString +** +** Description: Convert status code to status text. +** status: Status code +** +** Returns: None +** +*******************************************************************************/ +const char* SecureElement::eeStatusToString (UINT8 status) +{ + switch (status) + { + case NFC_NFCEE_STATUS_ACTIVE: + return("Connected/Active"); + case NFC_NFCEE_STATUS_INACTIVE: + return("Connected/Inactive"); + case NFC_NFCEE_STATUS_REMOVED: + return("Removed"); + } + return("?? Unknown ??"); +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Receive card-emulation related events from stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + switch (event) + { + case NFA_CE_UICC_LISTEN_CONFIGURED_EVT: + { + SyncEventGuard guard (mUiccListenEvent); + mUiccListenEvent.notifyOne (); + } + break; + } +} + + +/******************************************************************************* +** +** Function: routeToSecureElement +** +** Description: Adjust controller's listen-mode routing table so transactions +** are routed to the secure elements. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::routeToSecureElement () +{ + static const char fn [] = "SecureElement::routeToSecureElement"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + tNFA_TECHNOLOGY_MASK tech_mask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B; + bool retval = false; + + if (! mIsInit) + { + ALOGE ("%s: not init", fn); + return false; + } + + if (mCurrentRouteSelection == SecElemRoute) + { + ALOGE ("%s: already sec elem route", fn); + return true; + } + + if (mActiveEeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid EE handle", fn); + return false; + } + + adjustRoutes (SecElemRoute); + + { + unsigned long num = 0; + if (GetNumValue("UICC_LISTEN_TECH_MASK", &num, sizeof(num))) + tech_mask = num; + ALOGD ("%s: start UICC listen; h=0x%X; tech mask=0x%X", fn, mActiveEeHandle, tech_mask); + SyncEventGuard guard (mUiccListenEvent); + nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, tech_mask); + if (nfaStat == NFA_STATUS_OK) + { + mUiccListenEvent.wait (); + retval = true; + } + else + ALOGE ("%s: fail to start UICC listen", fn); + } + + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: routeToDefault +** +** Description: Adjust controller's listen-mode routing table so transactions +** are routed to the default destination. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::routeToDefault () +{ + static const char fn [] = "SecureElement::routeToDefault"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsInit) + { + ALOGE ("%s: not init", fn); + return false; + } + + if (mCurrentRouteSelection == DefaultRoute) + { + ALOGE ("%s: already default route", fn); + return true; + } + + { + ALOGD ("%s: stop UICC listen; EE h=0x%X", fn, mActiveEeHandle); + SyncEventGuard guard (mUiccListenEvent); + nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, 0); + if (nfaStat == NFA_STATUS_OK) + { + mUiccListenEvent.wait (); + retval = true; + } + else + ALOGE ("%s: fail to stop UICC listen", fn); + } + + adjustRoutes (DefaultRoute); + + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: isBusy +** +** Description: Whether controller is routing listen-mode events to +** secure elements or a pipe is connected. +** +** Returns: True if either case is true. +** +*******************************************************************************/ +bool SecureElement::isBusy () +{ + bool retval = (mCurrentRouteSelection == SecElemRoute) || mIsPiping; + ALOGD ("SecureElement::isBusy: %u", retval); + return retval; +} + diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h new file mode 100755 index 0000000..3542ac7 --- /dev/null +++ b/nci/jni/SecureElement.h @@ -0,0 +1,560 @@ +/***************************************************************************** +** +** Name: SecureElement.h +** +** Description: Communicate with secure elements that are attached +** to the NFC controller. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "SyncEvent.h" +#include "DataQueue.h" +#include "NfcJniUtil.h" +#include "RouteDataSet.h" +extern "C" +{ + #include "nfa_brcm_api.h" + #include "nfa_ee_api.h" + #include "nfa_hci_api.h" + #include "nfa_hci_defs.h" + #include "nfa_ce_api.h" +} + +#define MAX_TRANS_RECV_SIZE 1024 + +class SecureElement +{ +public: + tNFA_HANDLE mActiveEeHandle; + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get the SecureElement singleton object. + ** + ** Returns: SecureElement object. + ** + *******************************************************************************/ + static SecureElement& getInstance (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize all member variables. + ** native: Native data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool initialize (nfc_jni_native_data* native); + + + /******************************************************************************* + ** + ** Function: finalize + ** + ** Description: Release all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + void finalize (); + + + /******************************************************************************* + ** + ** Function: getListOfEeHandles + ** + ** Description: Get the list of handles of all execution environments. + ** e: Java Virtual Machine. + ** + ** Returns: List of handles of all execution environments. + ** + *******************************************************************************/ + jintArray getListOfEeHandles (JNIEnv* e); + + + /******************************************************************************* + ** + ** Function: activate + ** + ** Description: Turn on the secure element. + ** seID: ID of secure element. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool activate (jint seID); + + + /******************************************************************************* + ** + ** Function: deactivate + ** + ** Description: Turn off the secure element. + ** seID: ID of secure element. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool deactivate (jint seID); + + + /******************************************************************************* + ** + ** Function: connectEE + ** + ** Description: Connect to the execution environment. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool connectEE (); + + + /******************************************************************************* + ** + ** Function: disconnectEE + ** + ** Description: Disconnect from the execution environment. + ** seID: ID of secure element. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool disconnectEE (jint seID); + + + /******************************************************************************* + ** + ** Function: transceive + ** + ** Description: Send data to the secure element; read it's response. + ** xmitBuffer: Data to transmit. + ** xmitBufferSize: Length of data. + ** recvBuffer: Buffer to receive response. + ** recvBufferMaxSize: Maximum size of buffer. + ** recvBufferActualSize: Actual length of response. + ** timeoutMillisec: timeout in millisecond + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer, + INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec); + + + /******************************************************************************* + ** + ** Function: notifyRfFieldEvent + ** + ** Description: Notify the NFC service about RF field events from the stack. + ** isActive: Whether any secure element is activated. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyRfFieldEvent (bool isActive); + + + /******************************************************************************* + ** + ** Function: storeUiccInfo + ** + ** Description: Store a copy of the execution environment information from the stack. + ** info: execution environment information. + ** + ** Returns: None + ** + *******************************************************************************/ + void storeUiccInfo (tNFA_EE_DISCOVER_REQ& info); + + + /******************************************************************************* + ** + ** Function: getUiccId + ** + ** Description: Get the ID of the secure element. + ** eeHandle: Handle to the secure element. + ** uid: Array to receive the ID. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid); + + + /******************************************************************************* + ** + ** Function: getTechnologyList + ** + ** Description: Get all the technologies supported by a secure element. + ** eeHandle: Handle of secure element. + ** techList: List to receive the technologies. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList); + + + /******************************************************************************* + ** + ** Function: notifyTransactionListenersOfAid + ** + ** Description: Notify the NFC service about a transaction event from secure element. + ** aid: Buffer contains application ID. + ** aidLen: Length of application ID. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyTransactionListenersOfAid (const UINT8* aid, UINT8 aidLen); + + + /******************************************************************************* + ** + ** Function: notifyTransactionListenersOfTlv + ** + ** Description: Notify the NFC service about a transaction event from secure element. + ** The type-length-value contains AID and parameter. + ** tlv: type-length-value encoded in Basic Encoding Rule. + ** tlvLen: Length tlv. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyTransactionListenersOfTlv (const UINT8* tlv, UINT8 tlvLen); + + + /******************************************************************************* + ** + ** Function: connectionEventHandler + ** + ** Description: Receive card-emulation related events from stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: applyRoutes + ** + ** Description: Read route data from XML and apply them again + ** to every secure element. + ** + ** Returns: None + ** + *******************************************************************************/ + void applyRoutes (); + + + /******************************************************************************* + ** + ** Function: setActiveSeOverride + ** + ** Description: Specify which secure element to turn on. + ** activeSeOverride: ID of secure element + ** + ** Returns: None + ** + *******************************************************************************/ + void setActiveSeOverride (UINT8 activeSeOverride); + + + /******************************************************************************* + ** + ** Function: routeToSecureElement + ** + ** Description: Adjust controller's listen-mode routing table so transactions + ** are routed to the secure elements as specified in route.xml. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool routeToSecureElement (); + + + /******************************************************************************* + ** + ** Function: routeToDefault + ** + ** Description: Adjust controller's listen-mode routing table so transactions + ** are routed to the default destination specified in route.xml. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool routeToDefault (); + + + /******************************************************************************* + ** + ** Function: isBusy + ** + ** Description: Whether NFC controller is routing listen-mode events or a pipe is connected. + ** + ** Returns: True if either case is true. + ** + *******************************************************************************/ + bool isBusy (); + + + /******************************************************************************* + ** + ** Function getActualNumEe + ** + ** Description Returns number of secure elements we know about. + ** + ** Returns Number of secure elements we know about. + ** + *******************************************************************************/ + UINT8 getActualNumEe(); + + + /******************************************************************************* + ** + ** Function getSeVerInfo + ** + ** Description Gets version information and id for a secure element. The + ** seIndex parmeter is the zero based index of the secure + ** element to get verion info for. The version infommation + ** is returned as a string int the verInfo parameter. + ** + ** Returns ture on success, false on failure + ** + *******************************************************************************/ + bool getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid); + + +private: + enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute}; + static const int MAX_NUM_EE = 5; //max number of EE's + static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe + static const UINT8 STATIC_PIPE_0x71 = 0x71; //Broadcom's proprietary static pipe + static const UINT8 EVT_SEND_DATA = 0x10; //see specification ETSI TS 102 622 v9.0.0 (Host Controller Interface); section 9.3.3.3 + static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0 + static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1 + static SecureElement sSecElem; + + UINT8 mDestinationGate; //destination gate of the UICC + tNFA_HANDLE mNfaHciHandle; //NFA handle to NFA's HCI component + nfc_jni_native_data* mNativeData; + bool mIsInit; // whether EE is initialized + UINT8 mActualNumEe; // actual number of EE's reported by the stack + UINT8 mNumEePresent; // actual number of usable EE's + bool mbNewEE; + UINT8 mNewPipeId; + UINT8 mNewSourceGate; + UINT16 mActiveSeOverride; // active "enable" seid, 0 means activate all SEs + tNFA_STATUS mCommandStatus; //completion status of the last command + bool mIsPiping; //is a pipe connected to the controller? + RouteSelection mCurrentRouteSelection; + int mTransDataSize; + tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe + tNFA_EE_DISCOVER_REQ mUiccInfo; + tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg; + SyncEvent mEeRegisterEvent; + SyncEvent mHciRegisterEvent; + SyncEvent mEeSetModeEvent; + SyncEvent mPipeListEvent; + SyncEvent mCreatePipeEvent; + SyncEvent mPipeOpenedEvent; + SyncEvent mAllocateGateEvent; + SyncEvent mDeallocateGateEvent; + SyncEvent mRoutingEvent; + SyncEvent mUiccInfoEvent; + SyncEvent mUiccListenEvent; + SyncEvent mAidAddRemoveEvent; + SyncEvent mTransceiveEvent; + SyncEvent mVerInfoEvent; + UINT8 mVerInfo [3]; + UINT8 mTransData [MAX_TRANS_RECV_SIZE]; + UINT8 mHciBufferForStack [MAX_TRANS_RECV_SIZE]; + RouteDataSet mRouteDataSet; //routing data + std::vector mUsedAids; //AID's that are used in current routes + + + /******************************************************************************* + ** + ** Function: SecureElement + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + SecureElement (); + + + /******************************************************************************* + ** + ** Function: ~SecureElement + ** + ** Description: Release all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~SecureElement (); + + + /******************************************************************************* + ** + ** Function: nfaEeCallback + ** + ** Description: Receive execution environment-related events from stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: nfaHciCallback + ** + ** Description: Receive Host Controller Interface-related events from stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: findEeByHandle + ** + ** Description: Find information about an execution environment. + ** eeHandle: Handle to execution environment. + ** + ** Returns: Information about an execution environment. + ** + *******************************************************************************/ + tNFA_EE_INFO *findEeByHandle (tNFA_HANDLE eeHandle); + + + /******************************************************************************* + ** + ** Function: findUiccByHandle + ** + ** Description: Find information about an execution environment. + ** eeHandle: Handle of the execution environment. + ** + ** Returns: Information about the execution environment. + ** + *******************************************************************************/ + tNFA_EE_DISCOVER_INFO *findUiccByHandle (tNFA_HANDLE eeHandle); + + + /******************************************************************************* + ** + ** Function: getDefaultEeHandle + ** + ** Description: Get the handle to the execution environment. + ** + ** Returns: Handle to the execution environment. + ** + *******************************************************************************/ + tNFA_HANDLE getDefaultEeHandle (); + + + /******************************************************************************* + ** + ** Function: adjustRoutes + ** + ** Description: Adjust routes in the controller's listen-mode routing table. + ** selection: which set of routes to configure the controller. + ** + ** Returns: None + ** + *******************************************************************************/ + void adjustRoutes (RouteSelection selection); + + + /******************************************************************************* + ** + ** Function: adjustProtocolRoutes + ** + ** Description: Adjust default routing based on protocol in NFC listen mode. + ** isRouteToEe: Whether routing to EE (true) or host (false). + ** + ** Returns: None + ** + *******************************************************************************/ + void adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection); + + + /******************************************************************************* + ** + ** Function: adjustTechnologyRoutes + ** + ** Description: Adjust default routing based on technology in NFC listen mode. + ** isRouteToEe: Whether routing to EE (true) or host (false). + ** + ** Returns: None + ** + *******************************************************************************/ + void adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection); + + + /******************************************************************************* + ** + ** Function: getEeInfo + ** + ** Description: Get latest information about execution environments from stack. + ** + ** Returns: True if at least 1 EE is available. + ** + *******************************************************************************/ + bool getEeInfo (); + + + /******************************************************************************* + ** + ** Function: eeStatusToString + ** + ** Description: Convert status code to status text. + ** status: Status code + ** + ** Returns: None + ** + *******************************************************************************/ + static const char* eeStatusToString (UINT8 status); + + + /******************************************************************************* + ** + ** Function: encodeAid + ** + ** Description: Encode AID in type-length-value using Basic Encoding Rule. + ** tlv: Buffer to store TLV. + ** tlvMaxLen: TLV buffer's maximum length. + ** tlvActualLen: TLV buffer's actual length. + ** aid: Buffer of Application ID. + ** aidLen: Aid buffer's actual length. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool encodeAid (UINT8* tlv, UINT16 tlvMaxLen, UINT16& tlvActualLen, const UINT8* aid, UINT8 aidLen); +}; + diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h new file mode 100644 index 0000000..5828569 --- /dev/null +++ b/nci/jni/SyncEvent.h @@ -0,0 +1,167 @@ +/***************************************************************************** +** +** Name: SyncEvent.h +** +** Description: Synchronize two or more threads using a condition variable +** and a mutex. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "CondVar.h" +#include "Mutex.h" + + +class SyncEvent +{ +public: + /******************************************************************************* + ** + ** Function: ~SyncEvent + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~SyncEvent () + { + mMutex.unlock (); + } + + + /******************************************************************************* + ** + ** Function: start + ** + ** Description: Start a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void start () + { + mMutex.lock (); + } + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the thread and wait for the event to occur. + ** + ** Returns: None. + ** + *******************************************************************************/ + void wait () + { + mCondVar.wait (mMutex); + end (); + } + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the thread and wait for the event to occur. + ** millisec: Timeout in milliseconds. + ** + ** Returns: True if wait is successful; false if timeout occurs. + ** + *******************************************************************************/ + bool wait (long millisec) + { + bool retVal = mCondVar.wait (mMutex, millisec); + end (); + return retVal; + } + + + /******************************************************************************* + ** + ** Function: notifyOne + ** + ** Description: Notify a blocked thread that the event has occured. Unblocks it. + ** + ** Returns: None. + ** + *******************************************************************************/ + void notifyOne () + { + mCondVar.notifyOne (); + end (); + } + + + /******************************************************************************* + ** + ** Function: end + ** + ** Description: End a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void end () + { + mMutex.unlock (); + } + +private: + CondVar mCondVar; + Mutex mMutex; +}; + + +/*****************************************************************************/ +/*****************************************************************************/ + + +/***************************************************************************** +** +** Name: SyncEventGuard +** +** Description: Automatically start and end a synchronization event. +** +*****************************************************************************/ +class SyncEventGuard +{ +public: + /******************************************************************************* + ** + ** Function: SyncEventGuard + ** + ** Description: Start a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + SyncEventGuard (SyncEvent& event) + : mEvent (event) + { + event.start (); //automatically start operation + }; + + + /******************************************************************************* + ** + ** Function: ~SyncEventGuard + ** + ** Description: End a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~SyncEventGuard () + { + mEvent.end (); //automatically end operation + }; + +private: + SyncEvent& mEvent; +}; + diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..57a8295 --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_nci_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public static native boolean doSetScreenState(boolean state); + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + ///////////////////////////////////////////////////////////////// + // Broadcom: Since BCM2079x supports this, set NfcB max size. + //return 0; // PN544 does not support transceive of raw NfcB + return 253; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // TODO check BCM support + return false; + } + + public boolean enablePN544Quirks() { + return false; + } + + public byte[][] getWipeApdus() { + return null; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eb8410f --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,811 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = true; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + //status = doConnect(mTechHandles[i]); + status = doConnect(i); + } else { + // Connect to a tech with a different handle + Log.d(TAG,"Connect to a tech with a different handle"); + //status = reconnectWithStatus(mTechHandles[i]); + status = reconnectWithStatus(i); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + // special case for NDEF, this will cause switch to ISO_DEP frame intf + i = 0; + // status = 0; + } + status = reconnectWithStatus(i); + /* + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + // revised for NFCA... do allow to connect a -4 tag at this level. + Log.d(TAG,"Connect to a tech with same different handle (rf intf change)"); + status = reconnectWithStatus(i); + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + //status = 0; + } else { + status = 0; + } + */ + + + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + // Let native code decide whether the currently activated tag + // is formatable. Although the name of the JNI function refers + // to ISO-DEP, the JNI function checks all tag types. + return doIsIsoDepNdefFormatable(mTechPollBytes[0], + mTechActBytes[0]); + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + + //The technology must be removed from the mTechExtras array, + //just like the above arrays. + //Remove the specified element from the array, + //then shift the remaining elements by one. + if (mTechExtras != null) + { + Bundle[] mNewTechExtras = new Bundle[mTechExtras.length - 1]; + System.arraycopy(mTechExtras, 0, mNewTechExtras, 0, techIndex); + System.arraycopy(mTechExtras, techIndex + 1, mNewTechExtras, techIndex, + mTechExtras.length - techIndex - 1); + mTechExtras = mNewTechExtras; + } + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java index f969627..14544d2 100755 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -43,6 +43,20 @@ public class NativeNfcManager implements DeviceHost { private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; private static final long FIRMWARE_MODTIME_DEFAULT = -1; + //TODO: dont hardcode this + private static final byte[][] EE_WIPE_APDUS = { + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, + (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00}, + {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, + (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00}, + {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + }; + + static { System.loadLibrary("nfc_jni"); } @@ -310,6 +324,14 @@ public class NativeNfcManager implements DeviceHost { return false; } + public boolean enablePN544Quirks() { + return true; + } + + public byte[][] getWipeApdus() { + return EE_WIPE_APDUS; + } + private native String doDump(); @Override public String dump() { diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java index 047e3d5..a78a136 100644 --- a/src/com/android/nfc/DeviceHost.java +++ b/src/com/android/nfc/DeviceHost.java @@ -216,5 +216,9 @@ public interface DeviceHost { boolean getExtendedLengthApdusSupported(); + boolean enablePN544Quirks(); + + byte[][] getWipeApdus(); + String dump(); } diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 3e7a6b5..c42bdc0 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -101,8 +101,6 @@ public class NfcService extends Application implements DeviceHostListener { static final String PREF_FIRST_BOOT = "first_boot"; static final String PREF_AIRPLANE_OVERRIDE = "airplane_override"; - static final boolean PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE = true; - static final int MSG_NDEF_TAG = 0; static final int MSG_CARD_EMULATION = 1; static final int MSG_LLCP_LINK_ACTIVATION = 2; @@ -160,19 +158,6 @@ public class NfcService extends Application implements DeviceHostListener { public static final String EXTRA_MIFARE_BLOCK = "com.android.nfc_extras.extra.MIFARE_BLOCK"; - //TODO: dont hardcode this - private static final byte[][] EE_WIPE_APDUS = { - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, - (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00}, - {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, - (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00}, - {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, - }; - // NFC Execution Environment // fields below are protected by this private NativeNfcSecureElement mSecureElement; @@ -585,7 +570,12 @@ public class NfcService extends Application implements DeviceHostListener { void executeEeWipe() { // TODO: read SE reset list from /system/etc - byte[][]apdus = EE_WIPE_APDUS; + byte[][]apdus = mDeviceHost.getWipeApdus(); + + if (apdus == null) { + Log.d(TAG, "No wipe APDUs found"); + return; + } boolean tempEnable = mState == NfcAdapter.STATE_OFF; if (tempEnable) { @@ -1412,7 +1402,7 @@ public class NfcService extends Application implements DeviceHostListener { try { watchDog.start(); - if (PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE && mScreenState == SCREEN_STATE_OFF) { + if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) { /* TODO undo this after the LLCP stack is fixed. * Use a different sequence when turning the screen off to * workaround race conditions in pn544 libnfc. The race occurs -- cgit v1.1 From 343d00630cd9d5a80e003ab15a527acda45d2ae0 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 30 Jul 2012 16:09:59 -0700 Subject: Follow-up NFC code drop. From partner, uploaded 07/26/2012; modified to fit in new dhimpl/jni split. Change-Id: I3a8c04ab9427adc1295b7b46ec1308f98a2c2c5e --- nci/jni/NativeNfcManager.cpp | 44 +++++------ nci/jni/PeerToPeer.cpp | 88 ++++++++------------- nci/jni/PeerToPeer.h | 4 +- nci/jni/SecureElement.cpp | 89 +++++++++------------- nci/jni/SecureElement.h | 7 +- .../com/android/nfc/dhimpl/NativeNfcManager.java | 48 +----------- 6 files changed, 92 insertions(+), 188 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 0648852..d9be2e6 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -40,7 +40,7 @@ extern "C" extern UINT8 *p_nfa_dm_lptd_cfg; extern UINT8 *p_nfa_dm_start_up_cfg; extern const UINT8 nfca_version_string []; -extern "C" void nfa_app_post_nci_reset (); +extern "C" void nfa_app_post_nci_reset (UINT32 brcm_hw_id); namespace android { extern bool gIsTagDeactivating; @@ -513,28 +513,6 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) return JNI_FALSE; } - unsigned long num = 0; - - if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) - nat->tech_mask = num; - else - nat->tech_mask = DEFAULT_TECH_MASK; - - ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); - - // Always restore LPTD Configuration to the stack default. - if (sOriginalLptdCfg != NULL) - p_nfa_dm_lptd_cfg = sOriginalLptdCfg; - else - sOriginalLptdCfg = p_nfa_dm_lptd_cfg; - - // Override LPTD from the config file if it is found. - if (GetStrValue(NAME_LPTD_CFG, (char*)&sNewLptdCfg[0], sizeof(sNewLptdCfg))) - { - // Set stack pointer to use value. - p_nfa_dm_lptd_cfg = &sNewLptdCfg[0]; - } - PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); ALOGD ("%s: exit", __FUNCTION__); @@ -718,6 +696,23 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) ///////////////////////////////////////////////////////////////////////////////// // Add extra configuration here (work-arounds, etc.) + struct nfc_jni_native_data *nat = getNative(e, o); + + if ( nat ) + { + if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) + nat->tech_mask = num; + else + nat->tech_mask = DEFAULT_TECH_MASK; + + ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); + } + + // Always restore LPTD Configuration to the stack default. + if (sOriginalLptdCfg != NULL) + p_nfa_dm_lptd_cfg = sOriginalLptdCfg; + + // if this value is not set or set and non-zero, enable multi-technology responses. if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) NFA_SetMultiTechRsp(TRUE); @@ -1678,7 +1673,8 @@ bool nfcManager_isNfcActive() *******************************************************************************/ void nfaBrcmInitCallback (UINT32 brcm_hw_id) { - nfa_app_post_nci_reset (); + ALOGD ("%s: enter; brcm_hw_id=0x%X", __FUNCTION__, brcm_hw_id); + nfa_app_post_nci_reset (brcm_hw_id); } diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 4c02da2..d98aba5 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -58,9 +58,6 @@ PeerToPeer::PeerToPeer () memset (mClients, 0, sizeof(mClients)); if (GetNumValue ("APPL_TRACE_LEVEL", &num, sizeof (num))) mAppLogLevel = num; - - if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) - mP2pListenTechMask = num; } @@ -107,6 +104,11 @@ void PeerToPeer::initialize (long jniVersion) { ALOGD ("PeerToPeer::initialize"); mJniVersion = jniVersion; + + unsigned long num = 0; + + if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) + mP2pListenTechMask = num; } @@ -260,7 +262,7 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service if (sSnepServiceName.compare(serviceName) == 0) serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 - SyncEventGuard guard (pSrv->mListenEvent); + SyncEventGuard guard (pSrv->mRegServerEvent); stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); if (stat != NFA_STATUS_OK) { @@ -269,8 +271,8 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service return (false); } ALOGD ("%s: wait for listen-completion event", fn); - // Wait for NFA_P2P_LISTEN_EVT - pSrv->mListenEvent.wait (); + // Wait for NFA_P2P_REG_SERVER_EVT + pSrv->mRegServerEvent.wait (); if (pSrv->mNfaP2pServerHandle == NFA_HANDLE_INVALID) { @@ -566,7 +568,7 @@ bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) if ((pSrv = findServer (jniHandle)) == NULL) { - ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service handle: %u", fn, jniHandle); + ALOGE ("%s: unknown service handle: %u", fn, jniHandle); return (false); } @@ -1153,6 +1155,10 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff static const char fn [] = "PeerToPeer::receive"; ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); NfaConn *pConn = NULL; + tNFA_STATUS stat = NFA_STATUS_FAILED; + UINT32 actualDataLen2 = 0; + BOOLEAN isMoreData = TRUE; + bool retVal = false; if (jniHandle == mRcvFakeNppJniHandle) return (feedNppFromSnep(buffer, bufferLen, actualLen)); @@ -1165,28 +1171,24 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); - // Only wait for data if data queue is empty. - if (pConn->mInboundQ.isEmpty()) + while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) { - // And don't wait if we're disconnected. - if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + stat = NFA_P2pReadData (pConn->mNfaConnHandle, bufferLen, &actualDataLen2, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen2 > 0)) //received some data { - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); - SyncEventGuard guard (pConn->mReadEvent); - pConn->mReadEvent.wait(); + actualLen = (UINT16) actualDataLen2; + retVal = true; + break; } - - // If the connection was disconnected while we were blocked... - if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); { - ALOGD ("%s: already disconnected while waiting", fn); - return (false); + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.wait(); } - } + } //while - bool stat = pConn->mInboundQ.dequeue (buffer, bufferLen, actualLen); - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; client h=0x%X stat=%u actual len=%u", fn, pConn->mNfaConnHandle, stat, actualLen); - return stat; + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen); + return retVal; } @@ -1520,19 +1522,19 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev switch (p2pEvent) { - case NFA_P2P_LISTEN_EVT: // NFA_P2pRegisterServer() has started to listen - ALOGD ("%s: NFA_P2P_LISTEN_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, - eventData->listen.server_handle, eventData->listen.server_sap, eventData->listen.service_name); + case NFA_P2P_REG_SERVER_EVT: // NFA_P2pRegisterServer() has started to listen + ALOGD ("%s: NFA_P2P_REG_SERVER_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, + eventData->reg_server.server_handle, eventData->reg_server.server_sap, eventData->reg_server.service_name); - if ((pSrv = sP2p.findServer(eventData->listen.service_name)) == NULL) + if ((pSrv = sP2p.findServer(eventData->reg_server.service_name)) == NULL) { - ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service: %s", fn, eventData->listen.service_name); + ALOGE ("%s: NFA_P2P_REG_SERVER_EVT for unknown service: %s", fn, eventData->reg_server.service_name); } else { - SyncEventGuard guard (pSrv->mListenEvent); - pSrv->mNfaP2pServerHandle = eventData->listen.server_handle; - pSrv->mListenEvent.notifyOne(); //unblock registerServer() + SyncEventGuard guard (pSrv->mRegServerEvent); + pSrv->mNfaP2pServerHandle = eventData->reg_server.server_handle; + pSrv->mRegServerEvent.notifyOne(); //unblock registerServer() } break; @@ -1619,18 +1621,6 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev { ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, eventData->data.handle, eventData->data.remote_sap); - const int maxBufSize = 2 * 1024; - UINT8 buffer [maxBufSize]; - UINT32 actualDataLen = 0; - BOOLEAN isMoreData = TRUE; - while (isMoreData) - { - actualDataLen = 0; - isMoreData = FALSE; - tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); - if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) - pConn->mInboundQ.enqueue (buffer, actualDataLen); - } SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.notifyOne(); } @@ -1783,18 +1773,6 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev { ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, eventData->data.handle, eventData->data.remote_sap); - const int maxBufSize = 2 * 1024; - UINT8 buffer [maxBufSize]; - UINT32 actualDataLen = 0; - BOOLEAN isMoreData = TRUE; - while (isMoreData) - { - actualDataLen = 0; - isMoreData = FALSE; - tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); - if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) - pConn->mInboundQ.enqueue (buffer, actualDataLen); - } SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.notifyOne(); } diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index 00ead7f..166a6ac 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -10,7 +10,6 @@ *****************************************************************************/ #pragma once #include "SyncEvent.h" -#include "DataQueue.h" #include "NfcJniUtil.h" #include extern "C" @@ -595,7 +594,6 @@ public: UINT8 mRecvWindow; UINT16 mRemoteMaxInfoUnit; UINT8 mRemoteRecvWindow; - DataQueue mInboundQ; // store inbound data SyncEvent mReadEvent; // event for reading SyncEvent mCongEvent; // event for congestion SyncEvent mDisconnectingEvent; // event for disconnecting @@ -626,7 +624,7 @@ class P2pServer public: tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server tBRCM_JNI_HANDLE mJniHandle; // JNI Handle - SyncEvent mListenEvent; // for NFA_P2pRegisterServer() + SyncEvent mRegServerEvent; // for NFA_P2pRegisterServer() SyncEvent mConnRequestEvent; // for accept() std::string mServiceName; NfaConn *mServerConn[MAX_NFA_CONNS_PER_SERVER]; diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index f518650..08de696 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -67,12 +67,12 @@ SecureElement::SecureElement () mCommandStatus (NFA_STATUS_OK), mIsPiping (false), mCurrentRouteSelection (NoRoute), - mTransDataSize(0) + mActualResponseSize(0) { memset (&mEeInfo, 0, sizeof(mEeInfo)); memset (&mUiccInfo, 0, sizeof(mUiccInfo)); memset (&mHciCfg, 0, sizeof(mHciCfg)); - memset (mTransData, 0, MAX_TRANS_RECV_SIZE); + memset (mResponseData, 0, sizeof(mResponseData)); } @@ -189,7 +189,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) SyncEventGuard guard (mHciRegisterEvent); - nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE, MAX_TRANS_RECV_SIZE, mHciBufferForStack); + nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); @@ -810,15 +810,16 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* bool isSuccess = false; bool waitOk = false; - ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%d", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); + ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); { SyncEventGuard guard (mTransceiveEvent); - mTransDataSize = 0; + mActualResponseSize = 0; + memset (mResponseData, 0, sizeof(mResponseData)); if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71)) - nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer); + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); else - nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer); + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); if (nfaStat == NFA_STATUS_OK) { @@ -836,12 +837,12 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* } } - if (mTransDataSize > recvBufferMaxSize) + if (mActualResponseSize > recvBufferMaxSize) recvBufferActualSize = recvBufferMaxSize; else - recvBufferActualSize = mTransDataSize; + recvBufferActualSize = mActualResponseSize; - memcpy(recvBuffer, mTransData, recvBufferActualSize); + memcpy (recvBuffer, mResponseData, recvBufferActualSize); isSuccess = true; TheEnd: @@ -1668,12 +1669,14 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status); break; - case NFA_HCI_RSP_RCVD_EVT: - ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status:0x%X, pipe=0x%X, rsp_code:0x%X, rsp_len=%u", fn, - eventData->rsp_rcvd.status, eventData->rsp_rcvd.pipe, - eventData->rsp_rcvd.rsp_code, eventData->rsp_rcvd.rsp_len); + case NFA_HCI_RSP_RCVD_EVT: //response received from secure element + { + tNFA_HCI_RSP_RCVD& rsp_rcvd = eventData->rsp_rcvd; + ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status: 0x%X; code: 0x%X; pipe: 0x%X; len: %u", fn, + rsp_rcvd.status, rsp_rcvd.rsp_code, rsp_rcvd.pipe, rsp_rcvd.rsp_len); + } break; - + case NFA_HCI_GET_REG_RSP_EVT : ALOGD ("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn, eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len); @@ -1689,54 +1692,30 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event break; case NFA_HCI_EVENT_RCVD_EVT: - ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X", fn, - eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe); - if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71)) - { - //ISO7816 APDU arrived from sec elem's static pipes - ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; %u bytes from static pipe", fn, eventData->rcvd_evt.evt_len); - sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; - memcpy (sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X; data len: %u", fn, + eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len); + if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71)) + { + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; data from static pipe", fn); SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len; sSecElem.mTransceiveEvent.notifyOne (); - break; - } - switch (eventData->rcvd_evt.evt_code) + } + else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_POST_DATA) + { + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA", fn); + SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len; + sSecElem.mTransceiveEvent.notifyOne (); + } + else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_TRANSACTION) { - case NFA_HCI_EVT_POST_DATA: - { - ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA; len=%u", fn, eventData->rcvd_evt.evt_len); - sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; - memcpy(sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); - SyncEventGuard guard (sSecElem.mTransceiveEvent); - sSecElem.mTransceiveEvent.notifyOne (); - } - break; - - case NFA_HCI_EVT_HCI_END_OF_OPERATION: - break; - - case NFA_HCI_EVT_HOT_PLUG: - break; - - case NFA_HCI_EVT_CONNECTIVITY: - break; - - case NFA_HCI_EVT_TRANSACTION: ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn); // If we got an AID, notify any listeners if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) ) sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2], eventData->rcvd_evt.p_evt_buf[1]); - break; - - case NFA_HCI_EVT_OPERATION_ENDED: - break; - - default: - ALOGE ("%s: NFA_HCI_EVENT_RCVD_EVT; unknown event 0x%X ????", fn, eventData->rcvd_evt.evt_code); - break; } - break; //case NFA_HCI_EVENT_RCVD_EVT + break; default: ALOGE ("%s: unknown event code=0x%X ????", fn, event); diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index 3542ac7..8bfb8f5 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -23,7 +23,6 @@ extern "C" #include "nfa_ce_api.h" } -#define MAX_TRANS_RECV_SIZE 1024 class SecureElement { @@ -340,6 +339,7 @@ public: private: + static const unsigned int MAX_RESPONSE_SIZE = 1024; enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute}; static const int MAX_NUM_EE = 5; //max number of EE's static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe @@ -362,7 +362,7 @@ private: tNFA_STATUS mCommandStatus; //completion status of the last command bool mIsPiping; //is a pipe connected to the controller? RouteSelection mCurrentRouteSelection; - int mTransDataSize; + int mActualResponseSize; //number of bytes in the response received from secure element tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe tNFA_EE_DISCOVER_REQ mUiccInfo; tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg; @@ -381,8 +381,7 @@ private: SyncEvent mTransceiveEvent; SyncEvent mVerInfoEvent; UINT8 mVerInfo [3]; - UINT8 mTransData [MAX_TRANS_RECV_SIZE]; - UINT8 mHciBufferForStack [MAX_TRANS_RECV_SIZE]; + UINT8 mResponseData [MAX_RESPONSE_SIZE]; RouteDataSet mRouteDataSet; //routing data std::vector mUsedAids; //AID's that are used in current routes diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index 57a8295..f732cac 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -35,13 +35,7 @@ import java.io.File; */ public class NativeNfcManager implements DeviceHost { private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; + static final String PREF = "NciDeviceHost"; static { System.loadLibrary("nfc_nci_jni"); @@ -72,46 +66,6 @@ public class NativeNfcManager implements DeviceHost { @Override public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } } private native boolean doInitialize(); -- cgit v1.1 From 330ad0bde08e5b120acdec14edee72b0b6cde930 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Wed, 1 Aug 2012 11:31:08 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I340ff3b4e7d9822f677898ce942aa09b15ce0de3 Auto-generated-cl: translation import --- res/values-ar/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index d7ec39f..5eceaf8 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -8,14 +8,14 @@ "اكتمل تفاعل NFC" "المس لمنح هذا الشخص معلومات اتصالك." "تم تمكين NFC." - "المس لرسم شعاع" - "شعاع وارد..." - "اكتمل الشعاع" - "لم يكتمل الشعاع" - "تم إلغاء الشعاع" + "المس لتبادل البيانات" + "بيانات واردة..." + "اكتمل تبادل البيانات" + "لم يكتمل تبادل البيانات" + "تم إلغاء تبادل البيانات" "إلغاء" "المس ليتم العرض" - "جهاز المستلم لا يوفر نقل ملفات كبيرة عبر الشعاع." + "جهاز المستلم لا يوفر نقل ملفات كبيرة عبر تبادل البيانات." "جارٍ الاتصال..." "متصل" "تعذر الاتصال" -- cgit v1.1 From c2b3f02b1217c761d5247c3cda9444f0418b51cb Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 20 Jul 2012 15:09:37 -0400 Subject: Move NXP JNI and DeviceHost implementation into separate dir. (DO NOT MERGE) Preparation for the new NCI stack. The idea is to build either the NXP or the NCI stack, triggered by a makefile switch. To that end, move the DeviceHost and JNI implementations in their own directory, so we can build them only if needed. Change-Id: Ibb6aeb11f0bb887e153fd457860b1ad0e39e7933 --- Android.mk | 8 + jni/Android.mk | 35 - jni/com_android_nfc.cpp | 564 ----- jni/com_android_nfc.h | 259 -- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 -- jni/com_android_nfc_NativeLlcpServiceSocket.cpp | 227 -- jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ---- jni/com_android_nfc_NativeNfcManager.cpp | 2622 -------------------- jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ------ jni/com_android_nfc_NativeNfcTag.cpp | 1255 ---------- jni/com_android_nfc_NativeP2pDevice.cpp | 490 ---- jni/com_android_nfc_list.cpp | 210 -- jni/com_android_nfc_list.h | 49 - nxp/jni/Android.mk | 35 + nxp/jni/com_android_nfc.cpp | 564 +++++ nxp/jni/com_android_nfc.h | 259 ++ ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 ++ .../com_android_nfc_NativeLlcpServiceSocket.cpp | 227 ++ nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ++++ nxp/jni/com_android_nfc_NativeNfcManager.cpp | 2622 ++++++++++++++++++++ nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ++++++ nxp/jni/com_android_nfc_NativeNfcTag.cpp | 1255 ++++++++++ nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 490 ++++ nxp/jni/com_android_nfc_list.cpp | 210 ++ nxp/jni/com_android_nfc_list.h | 49 + .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 + .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 + .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 373 +++ .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 + nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 803 ++++++ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 + src/com/android/nfc/NfcService.java | 4 +- .../nfc/nxp/NativeLlcpConnectionlessSocket.java | 78 - .../android/nfc/nxp/NativeLlcpServiceSocket.java | 53 - src/com/android/nfc/nxp/NativeLlcpSocket.java | 99 - src/com/android/nfc/nxp/NativeNfcManager.java | 373 --- .../android/nfc/nxp/NativeNfcSecureElement.java | 67 - src/com/android/nfc/nxp/NativeNfcTag.java | 803 ------ src/com/android/nfc/nxp/NativeP2pDevice.java | 77 - 40 files changed, 8762 insertions(+), 8754 deletions(-) delete mode 100644 jni/Android.mk delete mode 100644 jni/com_android_nfc.cpp delete mode 100644 jni/com_android_nfc.h delete mode 100644 jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpServiceSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpSocket.cpp delete mode 100644 jni/com_android_nfc_NativeNfcManager.cpp delete mode 100755 jni/com_android_nfc_NativeNfcSecureElement.cpp delete mode 100644 jni/com_android_nfc_NativeNfcTag.cpp delete mode 100644 jni/com_android_nfc_NativeP2pDevice.cpp delete mode 100644 jni/com_android_nfc_list.cpp delete mode 100644 jni/com_android_nfc_list.h create mode 100644 nxp/jni/Android.mk create mode 100644 nxp/jni/com_android_nfc.cpp create mode 100644 nxp/jni/com_android_nfc.h create mode 100644 nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcManager.cpp create mode 100755 nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcTag.cpp create mode 100644 nxp/jni/com_android_nfc_NativeP2pDevice.cpp create mode 100644 nxp/jni/com_android_nfc_list.cpp create mode 100644 nxp/jni/com_android_nfc_list.h create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpServiceSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcManager.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcSecureElement.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcTag.java delete mode 100755 src/com/android/nfc/nxp/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index a041854..2cdfc68 100644 --- a/Android.mk +++ b/Android.mk @@ -6,6 +6,14 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) +ifeq ($(NFC_USE_NCI_STACK), true) + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nci) +else + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nxp) +endif + LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform diff --git a/jni/Android.mk b/jni/Android.mk deleted file mode 100644 index 8ae792a..0000000 --- a/jni/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES:= \ - com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ - com_android_nfc_NativeLlcpServiceSocket.cpp \ - com_android_nfc_NativeLlcpSocket.cpp \ - com_android_nfc_NativeNfcManager.cpp \ - com_android_nfc_NativeNfcTag.cpp \ - com_android_nfc_NativeP2pDevice.cpp \ - com_android_nfc_NativeNfcSecureElement.cpp \ - com_android_nfc_list.cpp \ - com_android_nfc.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/libnfc-nxp/src \ - external/libnfc-nxp/inc - -LOCAL_SHARED_LIBRARIES := \ - libnativehelper \ - libcutils \ - libutils \ - libnfc \ - libhardware - -#LOCAL_CFLAGS += -O0 -g - -LOCAL_MODULE := libnfc_jni -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp deleted file mode 100644 index d794d6e..0000000 --- a/jni/com_android_nfc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "errno.h" -#include "com_android_nfc.h" -#include "com_android_nfc_list.h" -#include "phLibNfcStatus.h" - -/* - * JNI Initialization - */ -jint JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - JNIEnv *e; - - ALOGD("NFC Service : loading JNI\n"); - - // Check JNI version - if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) - return JNI_ERR; - - android::vm = jvm; - - if (android::register_com_android_nfc_NativeNfcManager(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcTag(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) - return JNI_ERR; - - return JNI_VERSION_1_6; -} - -namespace android { - -extern struct nfc_jni_native_data *exported_nat; - -JavaVM *vm; - -/* - * JNI Utils - */ -JNIEnv *nfc_get_env() -{ - JNIEnv *e; - if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Current thread is not attached to VM"); - phLibNfc_Mgt_Recovery(); - abort(); - } - return e; -} - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) -{ - /* Create semaphore */ - if(sem_init(&pCallbackData->sem, 0, 0) == -1) - { - ALOGE("Semaphore creation failed (errno=0x%08x)", errno); - return false; - } - - /* Set default status value */ - pCallbackData->status = NFCSTATUS_FAILED; - - /* Copy the context */ - pCallbackData->pContext = pContext; - - /* Add to active semaphore list */ - if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to add the semaphore to the list"); - } - - return true; -} - -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) -{ - /* Destroy semaphore */ - if (sem_destroy(&pCallbackData->sem)) - { - ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); - } - - /* Remove from active semaphore list */ - if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to remove semaphore from the list"); - } - -} - -void nfc_cb_data_releaseAll() -{ - nfc_jni_callback_data* pCallbackData; - - while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) - { - pCallbackData->status = NFCSTATUS_FAILED; - sem_post(&pCallbackData->sem); - } -} - -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj) -{ - jclass cls; - jobject obj; - jmethodID ctor; - - cls = e->FindClass(clsname); - if(cls == NULL) - { - return -1; - ALOGD("Find class error\n"); - } - - - ctor = e->GetMethodID(cls, "", "()V"); - - obj = e->NewObject(cls, ctor); - if(obj == NULL) - { - return -1; - ALOGD("Create object error\n"); - } - - *cached_obj = e->NewGlobalRef(obj); - if(*cached_obj == NULL) - { - e->DeleteLocalRef(obj); - ALOGD("Global ref error\n"); - return -1; - } - - e->DeleteLocalRef(obj); - - return 0; -} - - -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - /* Retrieve native structure address */ - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mNative", "I"); - return (struct nfc_jni_native_data*)e->GetIntField(o, f); -} - -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) -{ - return exported_nat; -} - -static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; - -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) -{ - - pthread_mutexattr_t recursive_attr; - - pthread_mutexattr_init(&recursive_attr); - pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); - - if(nfc_jni_native_monitor == NULL) - { - nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); - } - - if(nfc_jni_native_monitor != NULL) - { - memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); - - if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) - { - ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) - { - ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(!listInit(&nfc_jni_native_monitor->sem_list)) - { - ALOGE("NFC Manager Semaphore List creation failed"); - return NULL; - } - - LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); - - if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) - { - ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) - { - ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); - return NULL; - } - -} - - return nfc_jni_native_monitor; -} - -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) -{ - return nfc_jni_native_monitor; -} - - -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mMode", "S"); - - return e->GetShortField(o, f); -} - - -int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) -{ - - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedTechIndex", "I"); - - return e->GetIntField(o, f); - -} - -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - int connectedTech = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); - - if ((connectedTechIndex != -1) && (techTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(techTypes))) { - jint* technologies = e->GetIntArrayElements(techTypes, 0); - if (technologies != NULL) { - connectedTech = technologies[connectedTechIndex]; - e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); - } - } - - return connectedTech; - -} - -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jint connectedLibNfcType = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); - jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); - - if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { - jint* types = e->GetIntArrayElements(libNfcTypes, 0); - if (types != NULL) { - connectedLibNfcType = types[connectedTechIndex]; - e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); - } - } - return connectedLibNfcType; - -} - -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedHandle", "I"); - - return e->GetIntField(o, f); -} - -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jintArray techtypes; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechList","[I"); - - /* Read the techtypes */ - techtypes = (jintArray) e->GetObjectField(o, f); - - return techtypes; -} - - - -//Display status code -const char* nfc_jni_get_status_name(NFCSTATUS status) -{ - #define STATUS_ENTRY(status) { status, #status } - - struct status_entry { - NFCSTATUS code; - const char *name; - }; - - const struct status_entry sNameTable[] = { - STATUS_ENTRY(NFCSTATUS_SUCCESS), - STATUS_ENTRY(NFCSTATUS_FAILED), - STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), - STATUS_ENTRY(NFCSTATUS_TARGET_LOST), - STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), - STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), - STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_SHUTDOWN), - STATUS_ENTRY(NFCSTATUS_ABORTED), - STATUS_ENTRY(NFCSTATUS_REJECTED ), - STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), - STATUS_ENTRY(NFCSTATUS_PENDING), - STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), - STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), - STATUS_ENTRY(NFCSTATUS_BUSY), - STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), - STATUS_ENTRY(NFCSTATUS_DESELECTED), - STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), - STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), - STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), - STATUS_ENTRY(NFCSTATUS_RF_ERROR), - STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), - STATUS_ENTRY(NFCSTATUS_INVALID_STATE), - STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), - STATUS_ENTRY(NFCSTATUS_RELEASED), - STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), - STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), - STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_READ_FAILED), - STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), - STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), - STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), - STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), - STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), - STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), - }; - - int i = sizeof(sNameTable)/sizeof(status_entry); - - while(i>0) - { - i--; - if (sNameTable[i].code == PHNFCSTATUS(status)) - { - return sNameTable[i].name; - } - } - - return "UNKNOWN"; -} - -int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, - int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { - bool found = false; - for (int i = 0; i < listSize; i++) { - if (techList[i] == techToAdd) { - found = true; - break; - } - } - if (!found && listSize < maxListSize) { - techList[listSize] = techToAdd; - handleList[listSize] = handleToAdd; - typeList[listSize] = typeToAdd; - return listSize + 1; - } - else { - return listSize; - } -} - - -#define MAX_NUM_TECHNOLOGIES 32 - -/* - * Utility to get a technology tree and a corresponding handle list from a detected tag. - */ -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* libnfcTypeList) -{ - int technologies[MAX_NUM_TECHNOLOGIES]; - int handles[MAX_NUM_TECHNOLOGIES]; - int libnfctypes[MAX_NUM_TECHNOLOGIES]; - - int index = 0; - // TODO: This counts from up to down because on multi-protocols, the - // ISO handle is usually the second, and we prefer the ISO. Should implement - // a method to find the "preferred handle order" and use that instead, - // since we shouldn't have dependencies on the tech list ordering. - for (int target = count - 1; target >= 0; target--) { - int type = devList[target].psRemoteDevInfo->RemDevType; - int handle = devList[target].hTargetDev; - switch (type) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - break; - } - case phNfc_eISO14443_4B_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO14443_3A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - case phNfc_eISO14443_B_PICC: - { - // TODO a bug in libnfc will cause 14443-3B only cards - // to be returned as this type as well, but these cards - // are very rare. Hence assume it's -4B - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO15693_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); - }break; - case phNfc_eMifare_PICC: - { - // We don't want to be too clever here; libnfc has already determined - // it's a Mifare, so we only check for UL, for all other tags - // we assume it's a mifare classic. This should make us more - // future-proof. - int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; - switch(sak) - { - case 0x00: - // could be UL or UL-C - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); - break; - default: - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); - break; - } - }break; - case phNfc_eFelica_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); - }break; - case phNfc_eJewel_PICC: - { - // Jewel represented as NfcA - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - default: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); - } - } - } - - // Build the Java arrays - if (techList != NULL) { - *techList = e->NewIntArray(index); - e->SetIntArrayRegion(*techList, 0, index, technologies); - } - - if (handleList != NULL) { - *handleList = e->NewIntArray(index); - e->SetIntArrayRegion(*handleList, 0, index, handles); - } - - if (libnfcTypeList != NULL) { - *libnfcTypeList = e->NewIntArray(index); - e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); - } -} - -} // namespace android diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h deleted file mode 100644 index a44bcf0..0000000 --- a/jni/com_android_nfc.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_JNI_H__ -#define __COM_ANDROID_NFC_JNI_H__ - -#define LOG_TAG "NFCJNI" - -#include -#include - -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include - -} -#include // for property_get - - -/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ -#define DISCOVERY_MODE_TAG_READER 0 -#define DISCOVERY_MODE_NFCIP1 1 -#define DISCOVERY_MODE_CARD_EMULATION 2 - -#define DISCOVERY_MODE_TABLE_SIZE 3 - -#define DISCOVERY_MODE_DISABLED 0 -#define DISCOVERY_MODE_ENABLED 1 - -#define MODE_P2P_TARGET 0 -#define MODE_P2P_INITIATOR 1 - -/* Properties values */ -#define PROPERTY_LLCP_LTO 0 -#define PROPERTY_LLCP_MIU 1 -#define PROPERTY_LLCP_WKS 2 -#define PROPERTY_LLCP_OPT 3 -#define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 -#define PROPERTY_NFC_DISCOVERY_F 6 -#define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 - -/* Error codes */ -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -/* Pre-defined card read/write state values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_UNKNOWN_TYPE -1 -#define NDEF_TYPE1_TAG 1 -#define NDEF_TYPE2_TAG 2 -#define NDEF_TYPE3_TAG 3 -#define NDEF_TYPE4_TAG 4 -#define NDEF_MIFARE_CLASSIC_TAG 101 -#define NDEF_ICODE_SLI_TAG 102 - -/* Pre-defined tag type values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_MODE_READ_ONLY 1 -#define NDEF_MODE_READ_WRITE 2 -#define NDEF_MODE_UNKNOWN 3 - - -/* Name strings for target types. These *must* match the values in TagTechnology.java */ -#define TARGET_TYPE_UNKNOWN -1 -#define TARGET_TYPE_ISO14443_3A 1 -#define TARGET_TYPE_ISO14443_3B 2 -#define TARGET_TYPE_ISO14443_4 3 -#define TARGET_TYPE_FELICA 4 -#define TARGET_TYPE_ISO15693 5 -#define TARGET_TYPE_NDEF 6 -#define TARGET_TYPE_NDEF_FORMATABLE 7 -#define TARGET_TYPE_MIFARE_CLASSIC 8 -#define TARGET_TYPE_MIFARE_UL 9 - -#define SMX_SECURE_ELEMENT_ID 11259375 - -/* Maximum byte length of an AID. */ -#define AID_MAXLEN 16 - -/* Utility macros for logging */ -#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN - -#if 0 - #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); - #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#else - #define LOG_CALLBACK(...) - #define TRACE(...) -#endif - -struct nfc_jni_native_data -{ - /* Thread handle */ - pthread_t thread; - int running; - - /* Our VM */ - JavaVM *vm; - int env_version; - - /* Reference to the NFCManager instance */ - jobject manager; - - /* Cached objects */ - jobject cached_NfcTag; - jobject cached_P2pDevice; - - /* Target discovery configuration */ - int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - - /* Secure Element selected */ - int seId; - - /* LLCP params */ - int lto; - int miu; - int wks; - int opt; - - /* Tag detected */ - jobject tag; - - /* Lib Status */ - NFCSTATUS status; - - /* p2p modes */ - int p2p_initiator_modes; - int p2p_target_modes; - -}; - -typedef struct nfc_jni_native_monitor -{ - /* Mutex protecting native library against reentrance */ - pthread_mutex_t reentrance_mutex; - - /* Mutex protecting native library against concurrency */ - pthread_mutex_t concurrency_mutex; - - /* List used to track pending semaphores waiting for callback */ - struct listHead sem_list; - - /* List used to track incoming socket requests (and associated sync variables) */ - LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; - pthread_mutex_t incoming_socket_mutex; - pthread_cond_t incoming_socket_cond; - -} nfc_jni_native_monitor_t; - -typedef struct nfc_jni_callback_data -{ - /* Semaphore used to wait for callback */ - sem_t sem; - - /* Used to store the status sent by the callback */ - NFCSTATUS status; - - /* Used to provide a local context to the callback */ - void* pContext; - -} nfc_jni_callback_data_t; - -typedef struct nfc_jni_listen_data -{ - /* LLCP server socket receiving the connection request */ - phLibNfc_Handle pServerSocket; - - /* LLCP socket created from the connection request */ - phLibNfc_Handle pIncomingSocket; - - /* List entries */ - LIST_ENTRY(nfc_jni_listen_data) entries; - -} nfc_jni_listen_data_t; - -/* TODO: treat errors and add traces */ -#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) -#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) -#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) -#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) - -namespace android { - -extern JavaVM *vm; - -JNIEnv *nfc_get_env(); - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); -void nfc_cb_data_releaseAll(); - -const char* nfc_jni_get_status_name(NFCSTATUS status); -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj); -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); - -int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* typeList); - -/* P2P */ -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); - -/* TAG */ -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); - -/* LLCP */ -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e); -int register_com_android_nfc_NativeNfcTag(JNIEnv *e); -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); - -} // namespace android - -#endif diff --git a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp deleted file mode 100644 index 188edb4..0000000 --- a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - pCallbackData->pContext = (void*)ssap; - TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_sendTo_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* -* Methods -*/ -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_SendTo()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SendTo(hRemoteDevice, - hLlcpSocket, - nsap, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) -{ - NFCSTATUS ret; - struct timespec ts; - uint8_t ssap; - jobject llcpPacket = NULL; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer; - jclass clsLlcpPacket; - jfieldID f; - jbyteArray receivedData = NULL; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create new LlcpPacket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) - { - ALOGE("Find LlcpPacket class error"); - goto clean_and_return; - } - - /* Get NativeConnectionless class object */ - clsLlcpPacket = e->GetObjectClass(llcpPacket); - if(e->ExceptionCheck()) - { - ALOGE("Get Object class error"); - goto clean_and_return; - } - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); - - sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); - sReceiveBuffer.length = linkMiu; - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - &cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ssap = (uint32_t)cb_data.pContext; - TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); - - /* Set Llcp Packet remote SAP */ - f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); - e->SetIntField(llcpPacket, f,(jbyte)ssap); - - /* Set Llcp Packet Buffer */ - ALOGD("Set LlcpPacket Data Buffer\n"); - f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); - receivedData = e->NewByteArray(sReceiveBuffer.length); - e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); - e->SetObjectField(llcpPacket, f, receivedData); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return llcpPacket; -} - -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - TRACE("Close Connectionless socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, - - {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, - - {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", - gMethods, NELEM(gMethods)); -} - -} // android namespace diff --git a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp deleted file mode 100644 index 92de3e4..0000000 --- a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode); -/* - * Callbacks - */ -static void nfc_jni_llcp_accept_socket_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -/* - * Utils - */ - -static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, - phLibNfc_Handle hServerSocket) -{ - nfc_jni_listen_data_t * pListenData; - phLibNfc_Handle pIncomingSocket = NULL; - - /* Look for a pending incoming connection on the current server */ - LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) - { - if (pListenData->pServerSocket == hServerSocket) - { - pIncomingSocket = pListenData->pIncomingSocket; - LIST_REMOVE(pListenData, entries); - free(pListenData); - break; - } - } - - return pIncomingSocket; -} - -/* - * Methods - */ -static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret = NFCSTATUS_SUCCESS; - struct timespec ts; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - jfieldID f; - jclass clsNativeLlcpSocket; - jobject clientSocket = NULL; - struct nfc_jni_callback_data cb_data; - phLibNfc_Handle hIncomingSocket, hServerSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Get server socket */ - hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Set socket options with the socket options of the service */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - - while(cb_data.status != NFCSTATUS_SUCCESS) - { - /* Wait for tag Notification */ - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { - pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); - } - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - /* Accept the incomming socket */ - TRACE("phLibNfc_Llcp_Accept()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Accept( hIncomingSocket, - &sOptions, - &sWorkingBuffer, - nfc_jni_llcp_transport_socket_err_callback, - nfc_jni_llcp_accept_socket_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - // NOTE: This may happen if link went down since incoming socket detected, then - // just drop it and start a new accept loop. - ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - continue; - } - TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ - ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); - } - } - - /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGD("LLCP Socket creation error"); - goto clean_and_return; - } - - /* Get NativeConnectionOriented class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGD("LLCP Socket get class object error"); - goto clean_and_return; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hIncomingSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - - TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return clientSocket; -} - -static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - TRACE("Close Service socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - /* TODO: implement accept abort */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("Close Service socket OK"); - return TRUE; - } - else - { - ALOGD("Close Service socket KO"); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_NativeLlcpServiceSocket_doAccept}, - - {"doClose", "()Z", - (void *)com_NativeLlcpServiceSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeLlcpSocket.cpp b/jni/com_android_nfc_NativeLlcpSocket.cpp deleted file mode 100644 index 0c0b830..0000000 --- a/jni/com_android_nfc_NativeLlcpSocket.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_disconnect_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - TRACE("Socket connected\n"); - } - else - { - ALOGD("Socket not connected:"); - switch(nErrCode) - { - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: - { - ALOGD("> SAP NOT ACTIVE\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: - { - ALOGD("> SAP NOT FOUND\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: - { - ALOGD("> CONNECT REJECTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: - { - ALOGD("> CONNECT NOT ACCEPTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: - { - ALOGD("> SOCKET NOT AVAILABLE\n"); - }break; - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - - - -static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Methods - */ -static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_Llcp_Connect(%d)",nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Connect(hRemoteDevice, - hLlcpSocket, - nSap, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("LLCP Connect request failed"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) -{ - NFCSTATUS ret; - struct timespec ts; - phNfc_sData_t serviceName = {0}; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Service socket */ - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - - TRACE("phLibNfc_Llcp_ConnectByUri()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, - hLlcpSocket, - &serviceName, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_Send()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Send(hRemoteDevice, - hLlcpSocket, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jint result = -1; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); - sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); - - TRACE("phLibNfc_Llcp_Recv()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Recv(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_PENDING) - { - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - } - else if (ret == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - else - { - /* Return status should be either SUCCESS or PENDING */ - ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - -clean_and_return: - if (sReceiveBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.miu; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.rw; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnect}, - - {"doConnectBy", "(Ljava/lang/String;)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, - - {"doClose", "()Z", - (void *)com_android_nfc_NativeLlcpSocket_doClose}, - - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeLlcpSocket_doSend}, - - {"doReceive", "([B)I", - (void *)com_android_nfc_NativeLlcpSocket_doReceive}, - - {"doGetRemoteSocketMiu", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, - - {"doGetRemoteSocketRw", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, -}; - - -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp deleted file mode 100644 index 704ee6a..0000000 --- a/jni/com_android_nfc_NativeNfcManager.cpp +++ /dev/null @@ -1,2622 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "com_android_nfc.h" - -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -extern uint32_t libnfc_llc_error_count; - -static phLibNfc_sConfig_t gDrvCfg; -void *gHWRef; -static phNfc_sData_t gInputParam; -static phNfc_sData_t gOutputParam; - -uint8_t device_connected_flag; -static bool driverConfigured = FALSE; - -static phLibNfc_Handle hLlcpHandle; -static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; -static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; - -static jmethodID cached_NfcManager_notifyNdefMessageListeners; -static jmethodID cached_NfcManager_notifyTransactionListeners; -static jmethodID cached_NfcManager_notifyLlcpLinkActivation; -static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; -static jmethodID cached_NfcManager_notifyTargetDeselected; - -static jmethodID cached_NfcManager_notifySeFieldActivated; -static jmethodID cached_NfcManager_notifySeFieldDeactivated; - -static jmethodID cached_NfcManager_notifySeApduReceived; -static jmethodID cached_NfcManager_notifySeMifareAccess; -static jmethodID cached_NfcManager_notifySeEmvCardRemoval; - -namespace android { - -phLibNfc_Handle storedHandle = 0; - -struct nfc_jni_native_data *exported_nat = NULL; - -/* Internal functions declaration */ -static void *nfc_jni_client_thread(void *arg); -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_se_set_mode_callback(void *context, - phLibNfc_Handle handle, NFCSTATUS status); -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status); -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); -static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); - -/* - * Deferred callback called when client thread must be exited - */ -static void client_kill_deferred_call(void* arg) -{ - struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; - - nat->running = FALSE; -} - -static void kill_client(nfc_jni_native_data *nat) -{ - phDal4Nfc_Message_Wrapper_t wrapper; - phLibNfc_DeferredCall_t *pMsg; - - usleep(50000); - - ALOGD("Terminating client thread..."); - - pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); - pMsg->pCallback = client_kill_deferred_call; - pMsg->pParameter = (void*)nat; - - wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; - wrapper.msg.pMsgData = pMsg; - wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); - - phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); -} - -static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_ioctl_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_deinit_download_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) -{ - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - struct timespec ts; - NFCSTATUS status = NFCSTATUS_FAILED; - phLibNfc_StackCapabilities_t caps; - struct nfc_jni_callback_data cb_data; - bool result; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - if(update) - { - //deinit - TRACE("phLibNfc_Mgt_DeInitialize() (download)"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts)) - { - ALOGW("Deinitialization timed out (download)"); - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("Deinitialization FAILED (download)"); - } - TRACE("Deinitialization SUCCESS (download)"); - } - - result = performDownload(nat, false); - - if (!result) { - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - status = cb_data.status; - goto clean_and_return; - } - - /* ====== CAPABILITIES ======= */ - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /*Download is successful*/ - status = NFCSTATUS_SUCCESS; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return status; -} - -static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) -{ - char value[PROPERTY_VALUE_MAX]; - int result = FALSE; - NFCSTATUS status; - - /* ====== CONFIGURE DRIVER ======= */ - /* Configure hardware link */ - gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); - - TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); - REENTRANCE_UNLOCK(); - if(status == NFCSTATUS_ALREADY_INITIALISED) { - ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) - { - ALOGE("pthread_create failed"); - goto clean_and_return; - } - - driverConfigured = TRUE; - -clean_and_return: - return result; -} - -static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) -{ - int result = FALSE; - NFCSTATUS status; - - /* Unconfigure driver */ - TRACE("phLibNfc_Mgt_UnConfigureDriver()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); - } - else - { - ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = TRUE; - } - - driverConfigured = FALSE; - - return result; -} - -/* Initialization function */ -static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { - struct timespec ts; - uint8_t resp[16]; - NFCSTATUS status; - phLibNfc_StackCapabilities_t caps; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; - phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; - struct nfc_jni_callback_data cb_data; - uint8_t firmware_status; - uint8_t update = TRUE; - int result = JNI_FALSE; - const hw_module_t* hw_module; - nfc_pn544_device_t* pn544_dev = NULL; - int ret = 0; - ALOGD("Start Initialization\n"); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Get EEPROM values and device port from product-specific settings */ - ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); - if (ret) { - ALOGE("hw_get_module() failed."); - goto clean_and_return; - } - ret = nfc_pn544_open(hw_module, &pn544_dev); - if (ret) { - ALOGE("Could not open pn544 hw_module."); - goto clean_and_return; - } - if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { - ALOGE("Could not load EEPROM settings"); - goto clean_and_return; - } - - /* Reset device connected handle */ - device_connected_flag = 0; - - /* Reset stored handle */ - storedHandle = 0; - - /* Initialize Driver */ - if(!driverConfigured) - { - nfc_jni_configure_driver(nat); - } - - /* ====== INITIALIZE ======= */ - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - update = FALSE; - goto force_download; - } - TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - update = FALSE; - goto force_download; - } - - /* ====== CAPABILITIES ======= */ - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /* ====== FIRMWARE VERSION ======= */ - if(caps.psDevCapabilities.firmware_update_info) - { -force_download: - for (i=0; i<3; i++) - { - TRACE("Firmware version not UpToDate"); - status = nfc_jni_download_locked(nat, update); - if(status == NFCSTATUS_SUCCESS) - { - ALOGI("Firmware update SUCCESS"); - break; - } - ALOGW("Firmware update FAILED"); - update = FALSE; - } - if(i>=3) - { - ALOGE("Unable to update firmware, giving up"); - goto clean_and_return; - } - } - else - { - TRACE("Firmware version UpToDate"); - } - /* ====== EEPROM SETTINGS ======= */ - - // Update EEPROM settings - TRACE("****** START EEPROM SETTINGS UPDATE ******"); - for (i = 0; i < pn544_dev->num_eeprom_settings; i++) - { - char eeprom_property[PROPERTY_KEY_MAX]; - char eeprom_value[PROPERTY_VALUE_MAX]; - uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); - TRACE("> EEPROM SETTING: %d", i); - - // Check for override of this EEPROM value in properties - snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", - eeprom_base[1], eeprom_base[2]); - TRACE(">> Checking property: %s", eeprom_property); - if (property_get(eeprom_property, eeprom_value, "") == 2) { - int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); - ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", - eeprom_base[1], eeprom_base[2], eeprom_value_num); - eeprom_base[3] = eeprom_value_num; - } - - TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], - eeprom_base[3]); - gInputParam.buffer = eeprom_base; - gInputParam.length = 0x04; - gOutputParam.buffer = resp; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if (cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - } - TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); - - /* ====== SECURE ELEMENTS ======= */ - - REENTRANCE_LOCK(); - ALOGD("phLibNfc_SE_GetSecureElementList()"); - status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - - ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i < No_SE; i++) - { - if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); - } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); - } - - /* Set SE mode - Off */ - REENTRANCE_LOCK(); - status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, - phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - } - - /* ====== LLCP ======= */ - - /* LLCP Params */ - TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); - LlcpConfigInfo.miu = nat->miu; - LlcpConfigInfo.lto = nat->lto; - LlcpConfigInfo.wks = nat->wks; - LlcpConfigInfo.option = nat->opt; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, - nfc_jni_llcpcfg_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* ===== DISCOVERY ==== */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.Duration = 300000; /* in ms */ - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Register for the card emulation mode */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); - - - /* ====== END ======= */ - - ALOGI("NFC Initialized"); - - result = TRUE; - -clean_and_return: - if (result != TRUE) - { - if(nat) - { - kill_client(nat); - } - } - if (pn544_dev != NULL) { - nfc_pn544_close(pn544_dev); - } - nfc_cb_data_deinit(&cb_data); - - return result; -} - -static int is_user_build() { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.type", value, ""); - return !strncmp("user", value, PROPERTY_VALUE_MAX); -} - -/* - * Last-chance fallback when there is no clean way to recover - * Performs a software reset - */ -void emergency_recovery(struct nfc_jni_native_data *nat) { - if (!is_user_build()) { - ALOGE("emergency_recovery: force restart of NFC service"); - } else { - // dont recover immediately, so we can debug - unsigned int t; - for (t=1; t < 1000000; t <<= 1) { - ALOGE("emergency_recovery: NFC stack dead-locked"); - sleep(t); - } - } - phLibNfc_Mgt_Recovery(); - abort(); // force a noisy crash -} - -void nfc_jni_reset_timeout_values() -{ - REENTRANCE_LOCK(); - phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); - phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); - phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); - phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); - REENTRANCE_UNLOCK(); -} - -/* - * Restart the polling loop when unable to perform disconnect - */ -void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) -{ - nfc_jni_start_discovery_locked(nat, true); -} - - /* - * Utility to recover UID from target infos - */ -static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - phNfc_sData_t uid; - - switch(psRemoteDevInfo->RemDevType) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_3A_PICC: - case phNfc_eMifare_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; - break; - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; - uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); - break; - case phNfc_eFelica_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; - uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; - break; - case phNfc_eJewel_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; - break; - case phNfc_eISO15693_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; - break; - case phNfc_eNfcIP1_Target: - case phNfc_eNfcIP1_Initiator: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; - uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; - break; - default: - uid.buffer = NULL; - uid.length = 0; - break; - } - - return uid; -} - -/* - * NFC stack message processing - */ -static void *nfc_jni_client_thread(void *arg) -{ - struct nfc_jni_native_data *nat; - JNIEnv *e; - JavaVMAttachArgs thread_args; - phDal4Nfc_Message_Wrapper_t wrapper; - - nat = (struct nfc_jni_native_data *)arg; - - thread_args.name = "NFC Message Loop"; - thread_args.version = nat->env_version; - thread_args.group = NULL; - - nat->vm->AttachCurrentThread(&e, &thread_args); - pthread_setname_np(pthread_self(), "message"); - - TRACE("NFC client started"); - nat->running = TRUE; - while(nat->running == TRUE) - { - /* Fetch next message from the NFC stack message queue */ - if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, - sizeof(phLibNfc_Message_t), 0, 0) == -1) - { - ALOGE("NFC client received bad message"); - continue; - } - - switch(wrapper.msg.eMsgType) - { - case PH_LIBNFC_DEFERREDCALL_MSG: - { - phLibNfc_DeferredCall_t *msg = - (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); - - REENTRANCE_LOCK(); - msg->pCallback(msg->pParameter); - REENTRANCE_UNLOCK(); - - break; - } - } - } - TRACE("NFC client stopped"); - - nat->vm->DetachCurrentThread(); - - return NULL; -} - -extern uint8_t nfc_jni_is_ndef; -extern uint8_t *nfc_jni_ndef_buf; -extern uint32_t nfc_jni_ndef_buf_len; - -static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = -{ - 3, - { 0x46, 0x66, 0x6D } -}; - -/* - * Callbacks - */ - -/* P2P - LLCP callbacks */ -static void nfc_jni_llcp_linkStatus_callback(void *pContext, - phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) -{ - phFriNfc_Llcp_sLinkParameters_t sLinkParams; - JNIEnv *e; - NFCSTATUS status; - - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; - - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - /* Update link status */ - g_eLinkStatus = eLinkStatus; - - if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) - { - REENTRANCE_LOCK(); - status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGW("GetRemote Info failded - Status = %02x",status); - } - else - { - ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, - sLinkParams.miu, - sLinkParams.option, - sLinkParams.wks); - device_connected_flag = 1; - } - } - else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) - { - ALOGI("LLCP Link deactivated"); - free(pContextData); - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Reset incoming socket list */ - while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) - { - pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); - LIST_REMOVE(pListenData, entries); - free(pListenData); - } - - /* Notify manager that the LLCP is lost or deactivated */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } -} - -static void nfc_jni_checkLlcp_callback(void *context, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; - - LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, - phLibNfc_Handle hIncomingSocket) -{ - phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - - /* Store the connection request */ - pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); - if (pListenData == NULL) - { - ALOGE("Failed to create structure to handle incoming LLCP connection request"); - goto clean_and_return; - } - pListenData->pServerSocket = hServiceSocket; - pListenData->pIncomingSocket = hIncomingSocket; - LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); - - /* Signal pending accept operations that the list is updated */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - -clean_and_return: - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); -} - -void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode) -{ - PHNFC_UNUSED_VARIABLE(pContext); - - TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); - - if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) - { - ALOGW("Frame Rejected - Disconnected"); - } - else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) - { - ALOGD("Socket Disconnected"); - } -} - - -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_discover_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNoOfRemoteDev) -{ - // Always prefer p2p targets over other targets. Otherwise, select the first target - // reported. - uint8_t preferred_index = 0; - for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { - if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { - preferred_index = i; - } - } - return preferred_index; -} - -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status) -{ - JNIEnv *e; - NFCSTATUS ret; - jclass tag_cls = NULL; - jobject target_array; - jobject tag; - jmethodID ctor; - jfieldID f; - const char * typeName; - jbyteArray tagUid; - jbyteArray generalBytes = NULL; - struct nfc_jni_native_data *nat; - struct timespec ts; - phNfc_sData_t data; - int i; - int target_index = 0; // Target that will be reported (if multiple can be >0) - - nat = (struct nfc_jni_native_data *)pContext; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); - - /* Notify manager that a target was deselected */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); - TRACE("Discovered %d tags", uNofRemoteDev); - - target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); - - /* Reset device connected flag */ - device_connected_flag = 1; - phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; - phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - - tag_cls = e->GetObjectClass(nat->cached_P2pDevice); - if(e->ExceptionCheck()) - { - ALOGE("Get Object Class Error"); - kill_client(nat); - return; - } - - /* New target instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - /* Set P2P Target mode */ - f = e->GetFieldID(tag_cls, "mMode", "I"); - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - ALOGD("Discovered P2P Initiator"); - e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); - } - else - { - ALOGD("Discovered P2P Target"); - e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); - } - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - /* Set General Bytes */ - f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes length ="); - for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) - { - ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); - } - - generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - - e->SetByteArrayRegion(generalBytes, 0, - remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, - (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); - - e->SetObjectField(tag, f, generalBytes); - } - - /* Set tag handle */ - f = e->GetFieldID(tag_cls, "mHandle", "I"); - e->SetIntField(tag, f,(jint)remDevHandle); - TRACE("Target handle = 0x%08x",remDevHandle); - } - else - { - tag_cls = e->GetObjectClass(nat->cached_NfcTag); - if(e->ExceptionCheck()) - { - kill_client(nat); - return; - } - - /* New tag instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - bool multi_protocol = false; - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - TRACE("Multiple Protocol TAG detected\n"); - multi_protocol = true; - } - - /* Set tag UID */ - f = e->GetFieldID(tag_cls, "mUid", "[B"); - data = get_target_uid(remDevInfo); - tagUid = e->NewByteArray(data.length); - if(data.length > 0) - { - e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); - } - e->SetObjectField(tag, f, tagUid); - - /* Generate technology list */ - jintArray techList; - jintArray handleList; - jintArray typeList; - nfc_jni_get_technology_tree(e, psRemoteDevList, - multi_protocol ? uNofRemoteDev : 1, - &techList, &handleList, &typeList); - - /* Push the technology list into the java object */ - f = e->GetFieldID(tag_cls, "mTechList", "[I"); - e->SetObjectField(tag, f, techList); - - f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); - e->SetObjectField(tag, f, handleList); - - f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); - e->SetObjectField(tag, f, typeList); - - f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); - e->SetIntField(tag, f,(jint)-1); - - f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); - e->SetIntField(tag, f,(jint)-1); - } - - storedHandle = remDevHandle; - if (nat->tag != NULL) { - e->DeleteGlobalRef(nat->tag); - } - nat->tag = e->NewGlobalRef(tag); - - /* Notify the service */ - TRACE("Notify Nfc Service"); - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - /* Store the hanlde of the P2P device */ - hLlcpHandle = remDevHandle; - - /* Notify manager that new a P2P device was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - /* Notify manager that new a tag was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - e->DeleteLocalRef(tag); - } -} - -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_init_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_deinit_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Card Emulation callback */ -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) -{ - JNIEnv *e; - jobject tmp_array = NULL; - jobject mifare_block = NULL; - struct nfc_jni_native_data *nat; - phNfc_sData_t *aid; - phNfc_sData_t *mifare_command; - struct nfc_jni_callback_data *pCallbackData; - int i=0; - - LOG_CALLBACK("nfc_jni_transaction_callback", status); - - nat = (struct nfc_jni_native_data *)context; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_SUCCESS) - { - switch(evt_type) - { - case phLibNfc_eSE_EvtStartTransaction: - { - TRACE("> SE EVT_START_TRANSACTION"); - if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) - { - aid = &(evt_info->UiccEvtInfo.aid); - - ALOGD("> AID DETECTED"); - - if(aid != NULL) - { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); - } - ALOGD("> AID: %s", aid_str); - - tmp_array = e->NewByteArray(aid->length); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - goto error; - } - - TRACE("Notify Nfc Service"); - /* Notify manager that a new event occurred on a SE */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - ALOGD("> NO AID DETECTED"); - } - }break; - - case phLibNfc_eSE_EvtApduReceived: - { - phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); - TRACE("> SE EVT_APDU_RECEIVED"); - - if (apdu != NULL) { - TRACE(" APDU length=%d", apdu->length); - tmp_array = e->NewByteArray(apdu->length); - if (tmp_array == NULL) { - goto error; - } - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); - if (e->ExceptionCheck()) { - goto error; - } - } else { - TRACE(" APDU EMPTY"); - } - - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); - }break; - - case phLibNfc_eSE_EvtCardRemoval: - { - TRACE("> SE EVT_EMV_CARD_REMOVAL"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); - }break; - - case phLibNfc_eSE_EvtMifareAccess: - { - TRACE("> SE EVT_MIFARE_ACCESS"); - mifare_command = &(evt_info->UiccEvtInfo.aid); - TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); - tmp_array = e->NewByteArray(2); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); - }break; - - case phLibNfc_eSE_EvtFieldOn: - { - TRACE("> SE EVT_FIELD_ON"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); - }break; - - case phLibNfc_eSE_EvtFieldOff: - { - TRACE("> SE EVT_FIELD_OFF"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); - }break; - - default: - { - TRACE("Unknown SE event"); - }break; - } - } - else - { - ALOGE("SE transaction notification error"); - goto error; - } - - /* Function finished, now clean and return */ - goto clean_and_return; - - error: - /* In case of error, just discard the notification */ - ALOGE("Failed to send SE transaction notification"); - e->ExceptionClear(); - - clean_and_return: - if(tmp_array != NULL) - { - e->DeleteLocalRef(tmp_array); - } -} - -static void nfc_jni_se_set_mode_callback(void *pContext, - phLibNfc_Handle handle, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* - * NFCManager methods - */ - -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) -{ - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ - nfc_jni_reset_timeout_values(); - - /* Reload the p2p modes */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Start Polling loop */ - TRACE("****** Start NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, - nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - -static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) -{ - phLibNfc_sADD_Cfg_t discovery_cfg; - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - discovery_cfg.PollDevInfo.PollEnabled = 0; - discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; - discovery_cfg.NfcIP_Target_Mode = 0; - discovery_cfg.NfcIP_Tgt_Disable = TRUE; - - /* Start Polling loop */ - TRACE("****** Stop NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - - -static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nfc_jni_stop_discovery_locked(nat); - - CONCURRENCY_UNLOCK(); - -} - -static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - nat = nfc_jni_get_nat(e, o); - - /* Register callback for remote device notifications. - * Must re-register every time we turn on discovery, since other operations - * (such as opening the Secure Element) can change the remote device - * notification callback*/ - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", - nat->registry_info.Jewel==TRUE?"J":"", - nat->registry_info.MifareUL==TRUE?"UL":"", - nat->registry_info.MifareStd==TRUE?"Mi":"", - nat->registry_info.Felica==TRUE?"F":"", - nat->registry_info.ISO14443_4A==TRUE?"4A":"", - nat->registry_info.ISO14443_4B==TRUE?"4B":"", - nat->registry_info.NFC==TRUE?"P2P":"", - nat->registry_info.ISO15693==TRUE?"R":"", ret); - - nfc_jni_start_discovery_locked(nat, false); -clean_and_return: - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { - CONCURRENCY_LOCK(); - nfc_jni_reset_timeout_values(); - CONCURRENCY_UNLOCK(); -} - -static void setFelicaTimeout(jint timeout) { - // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. - // It can be set to 0 to disable the timeout altogether, in which case we - // use the sw watchdog as a fallback. - if (timeout <= 255) { - phLibNfc_SetFelicaTimeout(timeout); - } else { - // Disable hw timeout, use sw watchdog for timeout - phLibNfc_SetFelicaTimeout(0); - phLibNfc_SetHciTimeout(timeout); - } - -} -// Calculates ceiling log2 of value -static unsigned int log2(int value) { - unsigned int ret = 0; - bool isPowerOf2 = ((value & (value - 1)) == 0); - while ( (value >> ret) > 1 ) ret++; - if (!isPowerOf2) ret++; - return ret; -} - -// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X -// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X -// -// We keep the constant part of the formula in a static; note the factor -// 1000 off, which is due to the fact that the formula calculates seconds, -// but this method gets milliseconds as an argument. -static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; - -static int calcTimeout(int timeout_in_ms) { - // timeout = (256 * 16 / 13560000) * 2 ^ X - // First find the first X for which timeout > requested timeout - return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); -} - -static void setIsoDepTimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - // Then re-compute the actual timeout based on X - double actual_timeout = nxp_nfc_timeout_factor * (1 << value); - // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, - // but it will take some time to get back through the sw layers. - // 500 ms should be enough). - phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); - value |= 0x10; // bit 4 to enable timeout - phLibNfc_SetIsoXchgTimeout(value); - } - else { - // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout - // must be disabled completely, to prevent the PN544 from aborting - // the transaction. We reuse the HCI sw watchdog to catch the timeout - // in that case. - phLibNfc_SetIsoXchgTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static void setNfcATimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - phLibNfc_SetMifareRawTimeout(value); - } - else { - // Disable mifare raw timeout, use HCI sw watchdog instead - phLibNfc_SetMifareRawTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, - jint tech, jint timeout) { - bool success = false; - CONCURRENCY_LOCK(); - if (timeout <= 0) { - ALOGE("Timeout must be positive."); - return false; - } else { - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - setNfcATimeout(timeout); - success = true; - break; - case TARGET_TYPE_ISO14443_4: - setIsoDepTimeout(timeout); - success = true; - break; - case TARGET_TYPE_FELICA: - setFelicaTimeout(timeout); - success = true; - break; - default: - ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); - success = false; - } - } - CONCURRENCY_UNLOCK(); - return success; -} - -static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, - jint tech) { - int timeout = -1; - CONCURRENCY_LOCK(); - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - timeout = phLibNfc_GetMifareRawTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_ISO14443_4: - timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_FELICA: - timeout = phLibNfc_GetFelicaTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Felica timeout already in ms - } - break; - default: - ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); - break; - } - CONCURRENCY_UNLOCK(); - return timeout; -} - - -static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct nfc_jni_native_data *nat = NULL; - jclass cls; - jobject obj; - jfieldID f; - - TRACE("****** Init Native Structure ******"); - - /* Initialize native structure */ - nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); - if(nat == NULL) - { - ALOGD("malloc of nfc_jni_native_data failed"); - return FALSE; - } - memset(nat, 0, sizeof(*nat)); - e->GetJavaVM(&(nat->vm)); - nat->env_version = e->GetVersion(); - nat->manager = e->NewGlobalRef(o); - - cls = e->GetObjectClass(o); - f = e->GetFieldID(cls, "mNative", "I"); - e->SetIntField(o, f, (jint)nat); - - /* Initialize native cached references */ - cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); - - cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, - "notifyTransactionListeners", "([B)V"); - - cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, - "notifyTargetDeselected","()V"); - - cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, - "notifySeFieldActivated", "()V"); - - cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, - "notifySeFieldDeactivated", "()V"); - - cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, - "notifySeApduReceived", "([B)V"); - - cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, - "notifySeMifareAccess", "([B)V"); - - cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, - "notifySeEmvCardRemoval", "()V"); - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - TRACE("****** Init Native Structure OK ******"); - return TRUE; - -} - -/* Init/Deinit method */ -static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - int init_result = JNI_FALSE; -#ifdef TNFC_EMULATOR_ONLY - char value[PROPERTY_VALUE_MAX]; -#endif - jboolean result; - - CONCURRENCY_LOCK(); - -#ifdef TNFC_EMULATOR_ONLY - if (!property_get("ro.kernel.qemu", value, 0)) - { - ALOGE("NFC Initialization failed: not running in an emulator\n"); - goto clean_and_return; - } -#endif - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nat->seId = SMX_SECURE_ELEMENT_ID; - - nat->lto = 150; // LLCP_LTO - nat->miu = 128; // LLCP_MIU - // WKS indicates well-known services; 1 << sap for each supported SAP. - // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) - nat->wks = 0x13; // LLCP_WKS - nat->opt = 0; // LLCP_OPT - nat->p2p_initiator_modes = phNfc_eP2P_ALL; - nat->p2p_target_modes = 0x0E; // All passive except 106, active - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; - - nat->registry_info.MifareUL = TRUE; - nat->registry_info.MifareStd = TRUE; - nat->registry_info.ISO14443_4A = TRUE; - nat->registry_info.ISO14443_4B = TRUE; - nat->registry_info.Jewel = TRUE; - nat->registry_info.Felica = TRUE; - nat->registry_info.NFC = TRUE; - nat->registry_info.ISO15693 = TRUE; - - exported_nat = nat; - - /* Perform the initialization */ - init_result = nfc_jni_initialize(nat); - -clean_and_return: - CONCURRENCY_UNLOCK(); - - /* Convert the result and return */ - return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; -} - -static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) -{ - struct timespec ts; - NFCSTATUS status; - int result = JNI_FALSE; - struct nfc_jni_native_data *nat; - int bStackReset = FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Clear previous configuration */ - memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); - memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); - - /* Create the local semaphore */ - if (nfc_cb_data_init(&cb_data, NULL)) - { - TRACE("phLibNfc_Mgt_DeInitialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status == NFCSTATUS_PENDING) - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts) == -1) - { - ALOGW("Operation timed out"); - bStackReset = TRUE; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Failed to deinit the stack"); - bStackReset = TRUE; - } - } - else - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - bStackReset = TRUE; - } - nfc_cb_data_deinit(&cb_data); - } - else - { - ALOGE("Failed to create semaphore (errno=0x%08x)", errno); - bStackReset = TRUE; - } - - kill_client(nat); - - if(bStackReset == TRUE) - { - /* Complete deinit. failed, try hard restart of NFC */ - ALOGW("Reseting stack..."); - emergency_recovery(nat); - } - - result = nfc_jni_unconfigure_driver(nat); - - TRACE("NFC Deinitialized"); - - CONCURRENCY_UNLOCK(); - - return TRUE; -} - -/* Secure Element methods */ -static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { - NFCSTATUS ret; - jintArray list= NULL; - phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; - - TRACE("****** Get Secure Element List ******"); - - TRACE("phLibNfc_SE_GetSecureElementList()"); - REENTRANCE_LOCK(); - ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_SUCCESS) { - ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - return list; - } - TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - - TRACE("Nb SE: %d", se_count); - list =e->NewIntArray(se_count); - for (i = 0; i < se_count; i++) { - if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } - e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); - } - - e->DeleteLocalRef(list); - - return list; -} - -static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Select Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Virtual */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING) { - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Deselect Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Default */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, - nfc_jni_se_set_mode_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); - if (ret != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -/* Llcp methods */ - -static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - bool freeData = false; - jboolean result = JNI_FALSE; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data *cb_data; - - - CONCURRENCY_LOCK(); - - /* Memory allocation for cb_data - * This is on the heap because it is used by libnfc - * even after this call has succesfully finished. It is only freed - * upon link closure in nfc_jni_llcp_linkStatus_callback. - */ - cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(cb_data, (void*)nat)) - { - goto clean_and_return; - } - - /* Check LLCP compliancy */ - TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, - nfc_jni_checkLlcp_callback, - nfc_jni_llcp_linkStatus_callback, - (void*)cb_data); - REENTRANCE_UNLOCK(); - /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol - * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - freeData = true; - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data->sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data->status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(cb_data); - if (freeData) { - free(cb_data); - } - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Activate(hLlcpHandle); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_FALSE; - } -} - - - -static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, - jint nSap, jstring sn) -{ - NFCSTATUS ret; - jobject connectionlessSocket = NULL; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_native_data *nat; - phNfc_sData_t sWorkingBuffer = {NULL, 0}; - phNfc_sData_t serviceName = {NULL, 0}; - phLibNfc_Llcp_sLinkParameters_t sParams; - jclass clsNativeConnectionlessSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Allocate Working buffer length */ - phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); - sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, - NULL, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - - /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) - { - goto error; - } - - /* Get NativeConnectionless class object */ - clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); - if(e->ExceptionCheck()) - { - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); - e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); - TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); - - /* Set the miu link of the connectionless socket */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); - e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); - TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); - e->SetIntField(connectionlessSocket, f,(jint)nSap); - TRACE("Connectionless socket SAP = %d\n",nSap); - - return connectionlessSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - - if (sWorkingBuffer.buffer != NULL) { - free(sWorkingBuffer.buffer); - } - - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - phNfc_sData_t serviceName; - struct nfc_jni_native_data *nat; - jobject serviceSocket = NULL; - jclass clsNativeLlcpServiceSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - ret = phLibNfc_Llcp_Close(hLlcpSocket); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Listen( hLlcpSocket, - nfc_jni_llcp_transport_listen_socket_callback, - (void*)hLlcpSocket); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - /* Close created socket */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) - { - ALOGE("Llcp Socket object creation error"); - goto error; - } - - /* Get NativeLlcpServiceSocket class object */ - clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); - if(e->ExceptionCheck()) - { - ALOGE("Llcp Socket get object class error"); - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); - e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); - TRACE("Service socket Handle = %02x\n",hLlcpSocket); - - /* Set socket linear buffer length */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); - e->SetIntField(serviceSocket, f,(jint)linearBufferLength); - TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); - e->SetIntField(serviceSocket, f,(jint)miu); - TRACE("Service socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); - e->SetIntField(serviceSocket, f,(jint)rw); - TRACE("Service socket RW = %d\n",rw); - - return serviceSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) -{ - jobject clientSocket = NULL; - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - struct nfc_jni_native_data *nat; - jclass clsNativeLlcpSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - return NULL; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGE("Llcp socket object creation error"); - return NULL; - } - - /* Get NativeConnectionless class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGE("Get class object error"); - return NULL; - } - - /* Test if an SAP number is present */ - if(nSap != 0) - { - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - return NULL; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); - e->SetIntField(clientSocket, f,(jint)nSap); - TRACE("socket SAP = %d\n",nSap); - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hLlcpSocket); - TRACE("socket Handle = %02x\n",hLlcpSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - TRACE("socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - TRACE("socket RW = %d\n",rw); - - - return clientSocket; -} - -static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) -{ - TRACE("Last Error Status = 0x%02x",lastErrorStatus); - - if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) - { - return ERROR_BUFFER_TOO_SMALL; - } - else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) - { - return ERROR_INSUFFICIENT_RESOURCES; - } - else - { - return lastErrorStatus; - } -} - -static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) -{ - emergency_recovery(NULL); -} - -static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting init modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_initiator_modes = modes; -} - -static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting target modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_target_modes = modes; -} - -static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { - bool result = FALSE; - int load_result; - bool wasDisabled = FALSE; - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - NFCSTATUS status = NFCSTATUS_FAILED; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - result = FALSE; - goto clean_and_return; - } - - if (takeLock) - { - CONCURRENCY_LOCK(); - } - - /* Initialize Driver */ - if(!driverConfigured) - { - result = nfc_jni_configure_driver(nat); - wasDisabled = TRUE; - } - TRACE("com_android_nfc_NfcManager_doDownload()"); - - TRACE("Go in Download Mode"); - phLibNfc_Download_Mode(); - - TRACE("Load new Firmware Image"); - load_result = phLibNfc_Load_Firmware_Image(); - if(load_result != 0) - { - TRACE("Load new Firmware Image - status = %d",load_result); - result = FALSE; - goto clean_and_return; - } - - // Download - gInputParam.buffer = InputBuffer; - gInputParam.length = 0x01; - gOutputParam.buffer = OutputBuffer; - gOutputParam.length = 0x01; - - ALOGD("Download new Firmware"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - result = FALSE; - goto clean_and_return; - } - - /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we - try to download an old-style firmware on top of a new-style - firmware. Hence, this is expected behavior, and not an - error condition. */ - if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); - } - - /*Download is successful*/ - result = TRUE; -clean_and_return: - TRACE("phLibNfc_HW_Reset()"); - phLibNfc_HW_Reset(); - /* Deinitialize Driver */ - if(wasDisabled) - { - result = nfc_jni_unconfigure_driver(nat); - } - if (takeLock) - { - CONCURRENCY_UNLOCK(); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - return performDownload(nat, true); -} - -static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); - return e->NewStringUTF(buffer); -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doDownload", "()Z", - (void *)com_android_nfc_NfcManager_doDownload}, - - {"initializeNativeStructure", "()Z", - (void *)com_android_nfc_NfcManager_init_native_struc}, - - {"doInitialize", "()Z", - (void *)com_android_nfc_NfcManager_initialize}, - - {"doDeinitialize", "()Z", - (void *)com_android_nfc_NfcManager_deinitialize}, - - {"enableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_enableDiscovery}, - - {"doGetSecureElementList", "()[I", - (void *)com_android_nfc_NfcManager_doGetSecureElementList}, - - {"doSelectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doSelectSecureElement}, - - {"doDeselectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, - - {"doCheckLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doCheckLlcp}, - - {"doActivateLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doActivateLlcp}, - - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, - - {"doGetLastError", "()I", - (void *)com_android_nfc_NfcManager_doGetLastError}, - - {"disableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_disableDiscovery}, - - {"doSetTimeout", "(II)Z", - (void *)com_android_nfc_NfcManager_doSetTimeout}, - - {"doGetTimeout", "(I)I", - (void *)com_android_nfc_NfcManager_doGetTimeout}, - - {"doResetTimeouts", "()V", - (void *)com_android_nfc_NfcManager_doResetTimeouts}, - - {"doAbort", "()V", - (void *)com_android_nfc_NfcManager_doAbort}, - - {"doSetP2pInitiatorModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, - - {"doSetP2pTargetModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, - - {"doDump", "()Ljava/lang/String;", - (void *)com_android_nfc_NfcManager_doDump}, -}; - - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e) -{ - nfc_jni_native_monitor_t *nfc_jni_native_monitor; - - nfc_jni_native_monitor = nfc_jni_init_monitor(); - if(nfc_jni_native_monitor == NULL) - { - ALOGE("NFC Manager cannot recover native monitor %x\n", errno); - return -1; - } - - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", - gMethods, NELEM(gMethods)); -} - -} /* namespace android */ diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp deleted file mode 100755 index bf0bffc..0000000 --- a/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "com_android_nfc.h" - -static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; -static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; -static phNfc_sRemoteDevInformation_t* SecureElementInfo; -static int secureElementHandle; -extern void *gHWRef; -static int SecureElementTech; -extern uint8_t device_connected_flag; - -namespace android { - -static void com_android_nfc_jni_ioctl_callback ( void* pContext, - phNfc_sData_t* Outparam_Cb, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if (status == NFCSTATUS_SUCCESS ) - { - LOG_CALLBACK("> IOCTL successful",status); - } - else - { - LOG_CALLBACK("> IOCTL error",status); - } - - com_android_nfc_jni_ioctl_buffer = Outparam_Cb; - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); - - com_android_nfc_jni_transceive_buffer = pResBuffer; - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static void com_android_nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if(status==NFCSTATUS_SUCCESS) - { - LOG_CALLBACK("SE Set Mode is Successful",status); - TRACE("SE Handle: %lu", hSecureElement); - } - else - { - LOG_CALLBACK("SE Set Mode is failed\n ",status); - } - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - NFCSTATUS ret; - int i; - JNIEnv *e = nfc_get_env(); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); - } - else - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); - TRACE("Discovered %d secure elements", uNofRemoteDev); - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - bool foundHandle = false; - TRACE("Multiple Protocol supported\n"); - for (i=0; iRemDevType); - if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { - secureElementHandle = psRemoteDevList[i].hTargetDev; - foundHandle = true; - } - } - if (!foundHandle) { - ALOGE("Could not find ISO-DEP secure element"); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - } - else - { - secureElementHandle = psRemoteDevList->hTargetDev; - } - - TRACE("Secure Element Handle: 0x%08x", secureElementHandle); - - /* Set type name */ - jintArray techList; - nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); - - // TODO: Should use the "connected" technology, for now use the first - if ((techList != NULL) && e->GetArrayLength(techList) > 0) { - e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); - TRACE("Store Secure Element Info\n"); - SecureElementInfo = psRemoteDevList->psRemoteDevInfo; - - TRACE("Discovered secure element: tech=%d", SecureElementTech); - } - else { - ALOGE("Discovered secure element, but could not resolve tech"); - status = NFCSTATUS_FAILED; - } - - // This thread may not return to the virtual machine for a long time - // so make sure to delete the local refernce to the tech list. - e->DeleteLocalRef(techList); - } - -clean_and_return: - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - int semResult; - - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - uint8_t Output_Buff[10]; - uint8_t reg_value; - uint8_t mask_value; - struct nfc_jni_callback_data cb_data; - struct nfc_jni_callback_data cb_data_SE_Notification; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) - { - goto clean_and_return; - } - - /* Registery */ - registry_info.MifareUL = TRUE; - registry_info.MifareStd = TRUE; - registry_info.ISO14443_4A = TRUE; - registry_info.ISO14443_4B = TRUE; - registry_info.Jewel = TRUE; - registry_info.Felica = TRUE; - registry_info.NFC = FALSE; - - CONCURRENCY_LOCK(); - - TRACE("Open Secure Element"); - - /* Check if NFC device is already connected to a tag or P2P peer */ - if (device_connected_flag == 1) - { - ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); - goto clean_and_return; - } - - /* Test if External RF field is detected */ - InParam.buffer = ExternalRFDetected; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - /* Check the value */ - reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; - mask_value = reg_value & 0x40; - - if(mask_value == 0x40) - { - // There is an external RF field present, fail the open request - ALOGD("Unable to open SE connection, external RF Field detected"); - goto clean_and_return; - } - - /* Get Secure Element List */ - TRACE("phLibNfc_SE_GetSecureElementList()"); - ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); - if (ret == NFCSTATUS_SUCCESS) - { - TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i SMX detected"); - TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); - /* save SMARTMX index */ - SmartMX_detected = 1; - SmartMX_index = i; - } - } - - if(SmartMX_detected) - { - REENTRANCE_LOCK(); - TRACE("phLibNfc_RemoteDev_NtfRegister()"); - ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, - com_android_nfc_jni_open_secure_element_notification_callback, - (void *)&cb_data_SE_Notification); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("Register Notification error"); - goto clean_and_return; - } - - /* Set wired mode */ - REENTRANCE_LOCK(); - TRACE("phLibNfc_SE_SetMode: Wired mode"); - ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, - phLibNfc_SE_ActModeWired, - com_android_nfc_jni_smartMX_setModeCb, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING ) - { - ALOGE("\n> SE Set SmartMX mode ERROR \n" ); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("SE set mode failed"); - goto clean_and_return; - } - - TRACE("Waiting for notification"); - /* Wait for callback response */ - if(sem_wait(&cb_data_SE_Notification.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && - cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) - { - ALOGE("SE detection failed"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Connect Tag */ - CONCURRENCY_LOCK(); - TRACE("phLibNfc_RemoteDev_Connect(SMX)"); - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("CONNECT semaphore error"); - goto clean_and_return; - } - - /* Connect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Secure Element connect error"); - goto clean_and_return; - } - - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue | 0x40); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - /* Return the Handle of the SecureElement */ - return secureElementHandle; - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); - goto clean_and_return; - } - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - CONCURRENCY_UNLOCK(); - return 0; -} - - -static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) -{ - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - uint32_t SmartMX_Handle; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t Output_Buff[10]; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Close Secure element function "); - - CONCURRENCY_LOCK(); - /* Disconnect */ - TRACE("Disconnecting from SMX (handle = 0x%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, - NFC_SMARTMX_RELEASE, - com_android_nfc_jni_disconnect_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("\n> Disconnect SE ERROR \n" ); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue & 0xBF); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, - jobject o,jint handle, jbyteArray data) -{ - uint8_t offset = 0; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - - int tech = SecureElementTech; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Exchange APDU function "); - - CONCURRENCY_LOCK(); - - TRACE("Secure Element tech: %d\n", tech); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - /* Prepare transceive info structure */ - if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) - { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - else if(tech == TARGET_TYPE_ISO14443_4) - { - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - } - - transceive_info.sSendData.buffer = buf + offset; - transceive_info.sSendData.length = buflen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - com_android_nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("TRANSCEIVE semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("TRANSCEIVE error"); - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); - if(result != NULL) - { - e->SetByteArrayRegion(result, 0, - com_android_nfc_jni_transceive_buffer->length, - (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) -{ - TRACE("Get Secure element UID function "); - jbyteArray SecureElementUid; - - if(handle == secureElementHandle) - { - SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); - e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); - return SecureElementUid; - } - else - { - return NULL; - } -} - -static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) -{ - jintArray techList; - TRACE("Get Secure element Type function "); - - if(handle == secureElementHandle) - { - techList = e->NewIntArray(1); - e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); - return techList; - } - else - { - return NULL; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doNativeOpenSecureElementConnection", "()I", - (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, - {"doNativeDisconnectSecureElementConnection", "(I)Z", - (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, - {"doTransceive", "(I[B)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, - {"doGetUid", "(I)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, - {"doGetTechList", "(I)[I", - (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, -}; - -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp deleted file mode 100644 index dbf8dc9..0000000 --- a/jni/com_android_nfc_NativeNfcTag.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" -#include "phNfcHalTypes.h" - -static phLibNfc_Data_t nfc_jni_ndef_rw; -static phLibNfc_Handle handle; -uint8_t *nfc_jni_ndef_buf = NULL; -uint32_t nfc_jni_ndef_buf_len = 0; - -extern uint8_t device_connected_flag; - -namespace android { - -extern phLibNfc_Handle storedHandle; - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); -extern void nfc_jni_reset_timeout_values(); - -/* - * Callbacks - */ - static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_tag_rw_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - if (pCallbackData->pContext != NULL) { - // Store the remote dev info ptr in the callback context - // Note that this ptr will remain valid, it is tied to a statically - // allocated buffer in libnfc. - phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = - (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; - *ppRemoteDevInfo = psRemoteDevInfo; - } - - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_checkndef_callback(void *pContext, - phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_checkndef_callback", status); - phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); - if(status == NFCSTATUS_OK) - { - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; - nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); - if (pNdefInfo != NULL) *pNdefInfo = info; - } - else { - if (pNdefInfo != NULL) { - memset(pNdefInfo, 0, sizeof(*pNdefInfo)); - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_async_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; -} - -static phNfc_sData_t *nfc_jni_transceive_buffer; - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - nfc_jni_transceive_buffer = pResBuffer; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presencecheck_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_formatndef_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_readonly_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* Functions */ -static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, - jobject o) -{ - NFCSTATUS status; - phLibNfc_Handle handle = 0; - jbyteArray buf = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; - nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; - - TRACE("phLibNfc_Ndef_Read()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, - phLibNfc_Ndef_EBegin, - nfc_jni_tag_rw_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - buf = e->NewByteArray(nfc_jni_ndef_rw.length); - e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, - (jbyte *)nfc_jni_ndef_rw.buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - - return buf; -} - - -static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, - jobject o, jbyteArray buf) -{ - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); - nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_Ndef_Write()"); - TRACE("Ndef Handle :0x%x\n",handle); - TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * Utility to recover poll bytes from target infos - */ -static void set_target_pollBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); - - jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingPollBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - jint *techId = e->GetIntArrayElements(techList, 0); - int techListLength = e->GetArrayLength(techList); - - jbyteArray pollBytes = e->NewByteArray(0); - jobjectArray techPollBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(pollBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) - { - /* ISO14443-3A: ATQA/SENS_RES */ - case TARGET_TYPE_ISO14443_3A: - if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { - // Jewel ATQA is not read and stored by the PN544, but it is fixed - // at {0x00, 0x0C} in the spec. So eJewel can safely be - // translated to {0x00, 0x0C}. - const static jbyte JewelAtqA[2] = {0x00, 0x0C}; - pollBytes = e->NewByteArray(2); - e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); - } - else { - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); - } - break; - /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ - case TARGET_TYPE_ISO14443_3B: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); - break; - /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ - case TARGET_TYPE_FELICA: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - pollBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techPollBytes, tech, pollBytes); - } - - e->SetObjectField(tag, f, techPollBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); - -} - -/* - * Utility to recover activation bytes from target infos - */ -static void set_target_activationBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - - jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); - jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingActBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - int techListLength = e->GetArrayLength(techList); - jint *techId = e->GetIntArrayElements(techList, 0); - - jbyteArray actBytes = e->NewByteArray(0); - jobjectArray techActBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(actBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) { - - /* ISO14443-3A: SAK/SEL_RES */ - case TARGET_TYPE_ISO14443_3A: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); - break; - /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ - /* ISO14443-3B & ISO14443-4: HiLayerResp */ - case TARGET_TYPE_ISO14443_4: - // Determine whether -A or -B - if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); - e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); - } - else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); - e->SetByteArrayRegion(actBytes, 0, - psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); - } - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - actBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techActBytes, tech, actBytes); - } - e->SetObjectField(tag, f, techActBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); -} - -static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - // Success, set poll & act bytes - set_target_pollBytes(e, o, pRemDevInfo); - set_target_activationBytes(e, o, pRemDevInfo); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, - jobject o) -{ - // Reconnect is provided by libnfc by just calling connect again - // on the same handle. - int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - if (libNfcType != -1) { - // Note that some tag types are stateless, hence we do not reconnect - // those. Currently those are the Jewel and Iso15693 technologies. - if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); - return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); - } - else { - return NFCSTATUS_SUCCESS; - } - } - else { - return NFCSTATUS_REJECTED; - } -} - - -static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_connected_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Reset the stored handle */ - storedHandle = 0; - - nfc_jni_reset_timeout_values(); - - /* Disconnect */ - TRACE("Disconnecting from tag (%x)", handle); - - if (handle == -1) { - // Was never connected to any tag, exit - result = JNI_TRUE; - ALOGE("doDisconnect() - Target already disconnected"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, - nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - result = JNI_TRUE; - TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); - goto clean_and_return; - } - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static uint16_t -crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) -{ - uint16_t b, crc = init; - - do { - b = *msg++ ^ (crc & 0xFF); - b ^= (b << 4) & 0xFF; - crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); - } while( --len ); - - return crc; -} - -static void -nfc_insert_crc_a( uint8_t* msg, size_t len ) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - msg[len] = crc & 0xFF; - msg[len + 1] = (crc >> 8) & 0xFF; -} - -static void -nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - *byte1 = crc & 0xFF; - *byte2 = (crc >> 8) & 0xFF; -} - -static bool -crc_valid( uint8_t* msg, size_t len) -{ - uint8_t crcByte1, crcByte2; - - nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, - len - 2, &crcByte1, &crcByte2); - - if (msg[len - 2] == crcByte1 && - msg[len - 1] == crcByte2) { - return true; - } - else { - return false; - } - -} - -static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, - jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) -{ - uint8_t offset = 0; - // buf is the pointer to the JNI array and never overwritten, - // outbuf is passed into the transceive - it may be pointed to new memory - // to be extended with CRC. - uint8_t *buf = NULL; - uint32_t buflen; - - uint8_t *outbuf = NULL; - uint32_t outlen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - int selectedTech = 0; - int selectedLibNfcType = 0; - jint* technologies = NULL; - bool checkResponseCrc = false; - - jint *targetLost; - if (statusTargetLost != NULL) { - targetLost = e->GetIntArrayElements(statusTargetLost, 0); - if (targetLost != NULL) { - *targetLost = 0; - } - } else { - targetLost = NULL; - } - - memset(&transceive_info, 0, sizeof(transceive_info)); - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - selectedTech = nfc_jni_get_connected_technology(e, o); - selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - - buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = outlen = (uint32_t)e->GetArrayLength(data); - - switch (selectedTech) { - case TARGET_TYPE_FELICA: - transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - if (raw) { - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - break; - case TARGET_TYPE_ISO14443_3A: - // Check which libnfc type - if (selectedLibNfcType == phNfc_eJewel_PICC) { - // For the Jewel pipe, CRC is automatically computed - transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; - transceive_info.addr = 0; - } else { - if (raw) { - // Use Mifare Raw to implement a standard - // ISO14443-3A transceive, with CRC added - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - // Use the mifare pipe - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - - } - break; - case TARGET_TYPE_ISO14443_4: - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_ISO15693: - transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; - transceive_info.addr = 0; - break; - case TARGET_TYPE_UNKNOWN: - case TARGET_TYPE_ISO14443_3B: - // Not supported - goto clean_and_return; - default: - break; - } - - transceive_info.sSendData.buffer = outbuf + offset; - transceive_info.sSendData.length = outlen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - - /* Copy results back to Java * - * In case of NfcA and raw, also check the CRC in the response - * and cut it off in the returned data. - */ - if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { - if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { - result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length - 2, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } - } else { - result = e->NewByteArray(nfc_jni_transceive_buffer->length); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - if ((outbuf != buf) && (outbuf != NULL)) { - // Buf was extended and re-alloced with crc bytes, free separately - free(outbuf); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)buf, JNI_ABORT); - - if (targetLost != NULL) { - e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); - } - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, - jint libnfcType, jint javaType) -{ - jint ndefType = NDEF_UNKNOWN_TYPE; - - switch (libnfcType) { - case phNfc_eJewel_PICC: - ndefType = NDEF_TYPE1_TAG; - break; - case phNfc_eISO14443_3A_PICC: - ndefType = NDEF_TYPE2_TAG;; - break; - case phNfc_eFelica_PICC: - ndefType = NDEF_TYPE3_TAG; - break; - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - ndefType = NDEF_TYPE4_TAG; - break; - case phNfc_eMifare_PICC: - if (javaType == TARGET_TYPE_MIFARE_UL) { - ndefType = NDEF_TYPE2_TAG; - } else { - ndefType = NDEF_MIFARE_CLASSIC_TAG; - } - break; - case phNfc_eISO15693_PICC: - ndefType = NDEF_ICODE_SLI_TAG; - break; - default: - ndefType = NDEF_UNKNOWN_TYPE; - break; - } - return ndefType; -} - -static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) -{ - phLibNfc_Handle handle = 0; - jint status; - phLibNfc_ChkNdef_Info_t sNdefInfo; - struct nfc_jni_callback_data cb_data; - jint *ndef = e->GetIntArrayElements(ndefinfo, 0); - int apiCardState = NDEF_MODE_UNKNOWN; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - cb_data.pContext = &sNdefInfo; - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_Ndef_CheckNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); - - if (status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ndef[0] = sNdefInfo.MaxNdefMsgLength; - // Translate the card state to know values for the NFC API - switch (sNdefInfo.NdefCardState) { - case PHLIBNFC_NDEF_CARD_INITIALISED: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_READ_ONLY: - apiCardState = NDEF_MODE_READ_ONLY; - break; - case PHLIBNFC_NDEF_CARD_READ_WRITE: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_INVALID: - apiCardState = NDEF_MODE_UNKNOWN; - break; - } - ndef[1] = apiCardState; - -clean_and_return: - e->ReleaseIntArrayElements(ndefinfo, ndef, 0); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_RemoteDev_CheckPresence()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, - jobject o, jbyteArray pollBytes, jbyteArray actBytes) -{ - // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire - // is supported. - jboolean result = JNI_FALSE; - - // DESfire has one sak byte and 2 ATQA bytes - if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && - actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { - jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); - jbyte* act = e->GetByteArrayElements(actBytes, NULL); - if (act[0] == 0x20 && poll[1] == 0x03) { - uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; - // Identifies as DESfire, use get version cmd to be sure - jbyteArray versionCmd = e->NewByteArray(5); - e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); - jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, - versionCmd, JNI_TRUE, NULL); - if (respBytes != NULL) { - // Check whether the response matches a typical DESfire - // response. - // libNFC even does more advanced checking than we do - // here, and will only format DESfire's with a certain - // major/minor sw version and NXP as a manufacturer. - // We don't want to do such checking here, to avoid - // having to change code in multiple places. - // A succesful (wrapped) DESFire getVersion command returns - // 9 bytes, with byte 7 0x91 and byte 8 having status - // code 0xAF (these values are fixed and well-known). - int respLength = e->GetArrayLength(respBytes); - jbyte* resp = e->GetByteArrayElements(respBytes, NULL); - if (respLength == 9 && resp[7] == (jbyte)0x91 && - resp[8] == (jbyte)0xAF) { - result = JNI_TRUE; - } - e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); - } - } - e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); - e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); - } - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - phNfc_sData_t keyBuffer; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_RemoteDev_FormatNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t keyBuffer; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_ConvertToReadOnlyNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeNfcTag_doDisconnect}, - {"doReconnect", "()I", - (void *)com_android_nfc_NativeNfcTag_doReconnect}, - {"doHandleReconnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, - {"doTransceive", "([BZ[I)[B", - (void *)com_android_nfc_NativeNfcTag_doTransceive}, - {"doGetNdefType", "(II)I", - (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, - {"doCheckNdef", "([I)I", - (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, - {"doRead", "()[B", - (void *)com_android_nfc_NativeNfcTag_doRead}, - {"doWrite", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doWrite}, - {"doPresenceCheck", "()Z", - (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, - {"doIsIsoDepNdefFormatable", "([B[B)Z", - (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, - {"doNdefFormat", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, - {"doMakeReadonly", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, -}; - -int register_com_android_nfc_NativeNfcTag(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp deleted file mode 100644 index b3cc6e3..0000000 --- a/jni/com_android_nfc_NativeP2pDevice.cpp +++ /dev/null @@ -1,490 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -extern uint8_t device_connected_flag; - -namespace android { - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); - -/* - * Callbacks - */ -static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presence_check_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; - psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_receive_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - *ptr = data; - } - else - { - *ptr = NULL; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Functions - */ - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - /* Report the callback data and wake up the caller */ - pCallbackData->pContext = pResBuffer; - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - jclass target_cls = NULL; - jobject tag; - jmethodID ctor; - jfieldID f; - jbyteArray generalBytes = NULL; - phNfc_sData_t sGeneralBytes; - unsigned int i; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Set General Bytes */ - target_cls = e->GetObjectClass(o); - - f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes Length = %d", sGeneralBytes.length); - TRACE("General Bytes ="); - for(i=0;iNewByteArray(sGeneralBytes.length); - - e->SetByteArrayRegion(generalBytes, 0, - sGeneralBytes.length, - (jbyte *)sGeneralBytes.buffer); - - e->SetObjectField(o, f, generalBytes); - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - /* Restart the polling loop if the connection failed */ - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jboolean result = JNI_FALSE; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Disconnect */ - TRACE("Disconnecting from target (handle = 0x%x)", handle); - - /* NativeNfcTag waits for tag to leave the field here with presence check. - * We do not in P2P path because presence check is not safe while transceive may be - * in progress. - */ - - TRACE("phLibNfc_RemoteDev_Disconnect()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); - } - else - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, - jobject o, jbyteArray data) -{ - NFCSTATUS status; - uint8_t offset = 2; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - phNfc_sData_t * receive_buffer = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) - { - goto clean_and_return; - } - - /* Transceive*/ - TRACE("Transceive data to target (handle = 0x%x)", handle); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - TRACE("Buffer Length = %d\n", buflen); - - transceive_info.sSendData.buffer = buf; //+ offset; - transceive_info.sSendData.length = buflen; //- offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(receive_buffer->length); - if(result != NULL) - e->SetByteArrayRegion(result, 0, - receive_buffer->length, - (jbyte *)receive_buffer->buffer); - -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - - -static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( - JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct timespec ts; - phLibNfc_Handle handle; - jbyteArray buf = NULL; - static phNfc_sData_t *data; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)data)) - { - goto clean_and_return; - } - - /* Receive */ - TRACE("phLibNfc_RemoteDev_Receive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(data == NULL) - { - goto clean_and_return; - } - - buf = e->NewByteArray(data->length); - e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return buf; -} - -static jboolean com_android_nfc_NativeP2pDevice_doSend( - JNIEnv *e, jobject o, jbyteArray buf) -{ - NFCSTATUS status; - phNfc_sData_t data; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Send */ - TRACE("Send data to the Initiator (handle = 0x%x)", handle); - - data.length = (uint32_t)e->GetArrayLength(buf); - data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_RemoteDev_Send()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, - {"doTransceive", "([B)[B", - (void *)com_android_nfc_NativeP2pDevice_doTransceive}, - {"doReceive", "()[B", - (void *)com_android_nfc_NativeP2pDevice_doReceive}, - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeP2pDevice_doSend}, -}; - -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", - gMethods, NELEM(gMethods)); -} - -} // namepspace android diff --git a/jni/com_android_nfc_list.cpp b/jni/com_android_nfc_list.cpp deleted file mode 100644 index f0487d3..0000000 --- a/jni/com_android_nfc_list.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#undef LOG_TAG -#define LOG_TAG "NFC_LIST" - -bool listInit(listHead* pList) -{ - pList->pFirst = NULL; - if(pthread_mutex_init(&pList->mutex, NULL) == -1) - { - ALOGE("Mutex creation failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listDestroy(listHead* pList) -{ - bool bListNotEmpty = true; - while (bListNotEmpty) { - bListNotEmpty = listGetAndRemoveNext(pList, NULL); - } - - if(pthread_mutex_destroy(&pList->mutex) == -1) - { - ALOGE("Mutex destruction failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listAdd(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pLastNode; - bool result; - - /* Create node */ - pNode = (struct listNode*)malloc(sizeof(listNode)); - if (pNode == NULL) - { - result = false; - ALOGE("Failed to malloc"); - goto clean_and_return; - } - TRACE("Allocated node: %8p (%8p)", pNode, pData); - pNode->pData = pData; - pNode->pNext = NULL; - - pthread_mutex_lock(&pList->mutex); - - /* Add the node to the list */ - if (pList->pFirst == NULL) - { - /* Set the node as the head */ - pList->pFirst = pNode; - } - else - { - /* Seek to the end of the list */ - pLastNode = pList->pFirst; - while(pLastNode->pNext != NULL) - { - pLastNode = pLastNode->pNext; - } - - /* Add the node to the current list */ - pLastNode->pNext = pNode; - } - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listRemove(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pRemovedNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst == NULL) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - pNode = pList->pFirst; - if (pList->pFirst->pData == pData) - { - /* Get the removed node */ - pRemovedNode = pNode; - - /* Remove the first node */ - pList->pFirst = pList->pFirst->pNext; - } - else - { - while (pNode->pNext != NULL) - { - if (pNode->pNext->pData == pData) - { - /* Node found ! */ - break; - } - pNode = pNode->pNext; - } - - if (pNode->pNext == NULL) - { - /* Node not found */ - result = false; - ALOGE("Failed to deallocate (not found %8p)", pData); - goto clean_and_return; - } - - /* Get the removed node */ - pRemovedNode = pNode->pNext; - - /* Remove the node from the list */ - pNode->pNext = pNode->pNext->pNext; - } - - /* Deallocate the node */ - TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); - free(pRemovedNode); - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listGetAndRemoveNext(listHead* pList, void** ppData) -{ - struct listNode* pNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - /* Work on the first node */ - pNode = pList->pFirst; - - /* Return the data */ - if (ppData != NULL) - { - *ppData = pNode->pData; - } - - /* Remove and deallocate the node */ - pList->pFirst = pNode->pNext; - TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); - free(pNode); - - result = true; - -clean_and_return: - listDump(pList); - pthread_mutex_unlock(&pList->mutex); - return result; -} - -void listDump(listHead* pList) -{ - struct listNode* pNode = pList->pFirst; - - TRACE("Node dump:"); - while (pNode != NULL) - { - TRACE("- %8p (%8p)", pNode, pNode->pData); - pNode = pNode->pNext; - } -} diff --git a/jni/com_android_nfc_list.h b/jni/com_android_nfc_list.h deleted file mode 100644 index 22b4f09..0000000 --- a/jni/com_android_nfc_list.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_LIST_H__ -#define __COM_ANDROID_NFC_LIST_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct listNode -{ - void* pData; - struct listNode* pNext; -}; - -struct listHead -{ - listNode* pFirst; - pthread_mutex_t mutex; -}; - -bool listInit(listHead* pList); -bool listDestroy(listHead* pList); -bool listAdd(listHead* pList, void* pData); -bool listRemove(listHead* pList, void* pData); -bool listGetAndRemoveNext(listHead* pList, void** ppData); -void listDump(listHead* pList); - -#ifdef __cplusplus -} -#endif - -#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/nxp/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/nxp/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h new file mode 100644 index 0000000..a44bcf0 --- /dev/null +++ b/nxp/jni/com_android_nfc.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include +#include + +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#else + #define LOG_CALLBACK(...) + #define TRACE(...) +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..704ee6a --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2622 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "com_android_nfc.h" + +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +extern uint32_t libnfc_llc_error_count; + +static phLibNfc_sConfig_t gDrvCfg; +void *gHWRef; +static phNfc_sData_t gInputParam; +static phNfc_sData_t gOutputParam; + +uint8_t device_connected_flag; +static bool driverConfigured = FALSE; + +static phLibNfc_Handle hLlcpHandle; +static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; +static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; + +static jmethodID cached_NfcManager_notifyNdefMessageListeners; +static jmethodID cached_NfcManager_notifyTransactionListeners; +static jmethodID cached_NfcManager_notifyLlcpLinkActivation; +static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; +static jmethodID cached_NfcManager_notifyTargetDeselected; + +static jmethodID cached_NfcManager_notifySeFieldActivated; +static jmethodID cached_NfcManager_notifySeFieldDeactivated; + +static jmethodID cached_NfcManager_notifySeApduReceived; +static jmethodID cached_NfcManager_notifySeMifareAccess; +static jmethodID cached_NfcManager_notifySeEmvCardRemoval; + +namespace android { + +phLibNfc_Handle storedHandle = 0; + +struct nfc_jni_native_data *exported_nat = NULL; + +/* Internal functions declaration */ +static void *nfc_jni_client_thread(void *arg); +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_se_set_mode_callback(void *context, + phLibNfc_Handle handle, NFCSTATUS status); +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status); +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); +static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); + +/* + * Deferred callback called when client thread must be exited + */ +static void client_kill_deferred_call(void* arg) +{ + struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; + + nat->running = FALSE; +} + +static void kill_client(nfc_jni_native_data *nat) +{ + phDal4Nfc_Message_Wrapper_t wrapper; + phLibNfc_DeferredCall_t *pMsg; + + usleep(50000); + + ALOGD("Terminating client thread..."); + + pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); + pMsg->pCallback = client_kill_deferred_call; + pMsg->pParameter = (void*)nat; + + wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + wrapper.msg.pMsgData = pMsg; + wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); + + phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); +} + +static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_ioctl_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_deinit_download_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) +{ + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + struct timespec ts; + NFCSTATUS status = NFCSTATUS_FAILED; + phLibNfc_StackCapabilities_t caps; + struct nfc_jni_callback_data cb_data; + bool result; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + if(update) + { + //deinit + TRACE("phLibNfc_Mgt_DeInitialize() (download)"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts)) + { + ALOGW("Deinitialization timed out (download)"); + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("Deinitialization FAILED (download)"); + } + TRACE("Deinitialization SUCCESS (download)"); + } + + result = performDownload(nat, false); + + if (!result) { + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + status = cb_data.status; + goto clean_and_return; + } + + /* ====== CAPABILITIES ======= */ + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /*Download is successful*/ + status = NFCSTATUS_SUCCESS; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return status; +} + +static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) +{ + char value[PROPERTY_VALUE_MAX]; + int result = FALSE; + NFCSTATUS status; + + /* ====== CONFIGURE DRIVER ======= */ + /* Configure hardware link */ + gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); + + TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); + REENTRANCE_UNLOCK(); + if(status == NFCSTATUS_ALREADY_INITIALISED) { + ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) + { + ALOGE("pthread_create failed"); + goto clean_and_return; + } + + driverConfigured = TRUE; + +clean_and_return: + return result; +} + +static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) +{ + int result = FALSE; + NFCSTATUS status; + + /* Unconfigure driver */ + TRACE("phLibNfc_Mgt_UnConfigureDriver()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); + } + else + { + ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = TRUE; + } + + driverConfigured = FALSE; + + return result; +} + +/* Initialization function */ +static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { + struct timespec ts; + uint8_t resp[16]; + NFCSTATUS status; + phLibNfc_StackCapabilities_t caps; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; + phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; + struct nfc_jni_callback_data cb_data; + uint8_t firmware_status; + uint8_t update = TRUE; + int result = JNI_FALSE; + const hw_module_t* hw_module; + nfc_pn544_device_t* pn544_dev = NULL; + int ret = 0; + ALOGD("Start Initialization\n"); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Get EEPROM values and device port from product-specific settings */ + ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); + if (ret) { + ALOGE("hw_get_module() failed."); + goto clean_and_return; + } + ret = nfc_pn544_open(hw_module, &pn544_dev); + if (ret) { + ALOGE("Could not open pn544 hw_module."); + goto clean_and_return; + } + if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { + ALOGE("Could not load EEPROM settings"); + goto clean_and_return; + } + + /* Reset device connected handle */ + device_connected_flag = 0; + + /* Reset stored handle */ + storedHandle = 0; + + /* Initialize Driver */ + if(!driverConfigured) + { + nfc_jni_configure_driver(nat); + } + + /* ====== INITIALIZE ======= */ + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + update = FALSE; + goto force_download; + } + TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + update = FALSE; + goto force_download; + } + + /* ====== CAPABILITIES ======= */ + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /* ====== FIRMWARE VERSION ======= */ + if(caps.psDevCapabilities.firmware_update_info) + { +force_download: + for (i=0; i<3; i++) + { + TRACE("Firmware version not UpToDate"); + status = nfc_jni_download_locked(nat, update); + if(status == NFCSTATUS_SUCCESS) + { + ALOGI("Firmware update SUCCESS"); + break; + } + ALOGW("Firmware update FAILED"); + update = FALSE; + } + if(i>=3) + { + ALOGE("Unable to update firmware, giving up"); + goto clean_and_return; + } + } + else + { + TRACE("Firmware version UpToDate"); + } + /* ====== EEPROM SETTINGS ======= */ + + // Update EEPROM settings + TRACE("****** START EEPROM SETTINGS UPDATE ******"); + for (i = 0; i < pn544_dev->num_eeprom_settings; i++) + { + char eeprom_property[PROPERTY_KEY_MAX]; + char eeprom_value[PROPERTY_VALUE_MAX]; + uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); + TRACE("> EEPROM SETTING: %d", i); + + // Check for override of this EEPROM value in properties + snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", + eeprom_base[1], eeprom_base[2]); + TRACE(">> Checking property: %s", eeprom_property); + if (property_get(eeprom_property, eeprom_value, "") == 2) { + int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); + ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", + eeprom_base[1], eeprom_base[2], eeprom_value_num); + eeprom_base[3] = eeprom_value_num; + } + + TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], + eeprom_base[3]); + gInputParam.buffer = eeprom_base; + gInputParam.length = 0x04; + gOutputParam.buffer = resp; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if (cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + } + TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); + + /* ====== SECURE ELEMENTS ======= */ + + REENTRANCE_LOCK(); + ALOGD("phLibNfc_SE_GetSecureElementList()"); + status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + + ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i < No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); + } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); + } + + /* Set SE mode - Off */ + REENTRANCE_LOCK(); + status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, + phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + } + + /* ====== LLCP ======= */ + + /* LLCP Params */ + TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); + LlcpConfigInfo.miu = nat->miu; + LlcpConfigInfo.lto = nat->lto; + LlcpConfigInfo.wks = nat->wks; + LlcpConfigInfo.option = nat->opt; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, + nfc_jni_llcpcfg_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* ===== DISCOVERY ==== */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.Duration = 300000; /* in ms */ + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== END ======= */ + + ALOGI("NFC Initialized"); + + result = TRUE; + +clean_and_return: + if (result != TRUE) + { + if(nat) + { + kill_client(nat); + } + } + if (pn544_dev != NULL) { + nfc_pn544_close(pn544_dev); + } + nfc_cb_data_deinit(&cb_data); + + return result; +} + +static int is_user_build() { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", value, ""); + return !strncmp("user", value, PROPERTY_VALUE_MAX); +} + +/* + * Last-chance fallback when there is no clean way to recover + * Performs a software reset + */ +void emergency_recovery(struct nfc_jni_native_data *nat) { + if (!is_user_build()) { + ALOGE("emergency_recovery: force restart of NFC service"); + } else { + // dont recover immediately, so we can debug + unsigned int t; + for (t=1; t < 1000000; t <<= 1) { + ALOGE("emergency_recovery: NFC stack dead-locked"); + sleep(t); + } + } + phLibNfc_Mgt_Recovery(); + abort(); // force a noisy crash +} + +void nfc_jni_reset_timeout_values() +{ + REENTRANCE_LOCK(); + phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); + phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); + phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); + phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); + REENTRANCE_UNLOCK(); +} + +/* + * Restart the polling loop when unable to perform disconnect + */ +void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) +{ + nfc_jni_start_discovery_locked(nat, true); +} + + /* + * Utility to recover UID from target infos + */ +static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + phNfc_sData_t uid; + + switch(psRemoteDevInfo->RemDevType) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_3A_PICC: + case phNfc_eMifare_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; + break; + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; + uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); + break; + case phNfc_eFelica_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; + uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; + break; + case phNfc_eJewel_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; + break; + case phNfc_eISO15693_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; + break; + case phNfc_eNfcIP1_Target: + case phNfc_eNfcIP1_Initiator: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; + uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; + break; + default: + uid.buffer = NULL; + uid.length = 0; + break; + } + + return uid; +} + +/* + * NFC stack message processing + */ +static void *nfc_jni_client_thread(void *arg) +{ + struct nfc_jni_native_data *nat; + JNIEnv *e; + JavaVMAttachArgs thread_args; + phDal4Nfc_Message_Wrapper_t wrapper; + + nat = (struct nfc_jni_native_data *)arg; + + thread_args.name = "NFC Message Loop"; + thread_args.version = nat->env_version; + thread_args.group = NULL; + + nat->vm->AttachCurrentThread(&e, &thread_args); + pthread_setname_np(pthread_self(), "message"); + + TRACE("NFC client started"); + nat->running = TRUE; + while(nat->running == TRUE) + { + /* Fetch next message from the NFC stack message queue */ + if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, + sizeof(phLibNfc_Message_t), 0, 0) == -1) + { + ALOGE("NFC client received bad message"); + continue; + } + + switch(wrapper.msg.eMsgType) + { + case PH_LIBNFC_DEFERREDCALL_MSG: + { + phLibNfc_DeferredCall_t *msg = + (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); + + REENTRANCE_LOCK(); + msg->pCallback(msg->pParameter); + REENTRANCE_UNLOCK(); + + break; + } + } + } + TRACE("NFC client stopped"); + + nat->vm->DetachCurrentThread(); + + return NULL; +} + +extern uint8_t nfc_jni_is_ndef; +extern uint8_t *nfc_jni_ndef_buf; +extern uint32_t nfc_jni_ndef_buf_len; + +static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = +{ + 3, + { 0x46, 0x66, 0x6D } +}; + +/* + * Callbacks + */ + +/* P2P - LLCP callbacks */ +static void nfc_jni_llcp_linkStatus_callback(void *pContext, + phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) +{ + phFriNfc_Llcp_sLinkParameters_t sLinkParams; + JNIEnv *e; + NFCSTATUS status; + + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; + + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + /* Update link status */ + g_eLinkStatus = eLinkStatus; + + if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) + { + REENTRANCE_LOCK(); + status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGW("GetRemote Info failded - Status = %02x",status); + } + else + { + ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, + sLinkParams.miu, + sLinkParams.option, + sLinkParams.wks); + device_connected_flag = 1; + } + } + else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) + { + ALOGI("LLCP Link deactivated"); + free(pContextData); + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Reset incoming socket list */ + while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) + { + pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); + LIST_REMOVE(pListenData, entries); + free(pListenData); + } + + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } +} + +static void nfc_jni_checkLlcp_callback(void *context, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; + + LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, + phLibNfc_Handle hIncomingSocket) +{ + phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + + /* Store the connection request */ + pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); + if (pListenData == NULL) + { + ALOGE("Failed to create structure to handle incoming LLCP connection request"); + goto clean_and_return; + } + pListenData->pServerSocket = hServiceSocket; + pListenData->pIncomingSocket = hIncomingSocket; + LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); + + /* Signal pending accept operations that the list is updated */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + +clean_and_return: + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); +} + +void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode) +{ + PHNFC_UNUSED_VARIABLE(pContext); + + TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); + + if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) + { + ALOGW("Frame Rejected - Disconnected"); + } + else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) + { + ALOGD("Socket Disconnected"); + } +} + + +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_discover_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNoOfRemoteDev) +{ + // Always prefer p2p targets over other targets. Otherwise, select the first target + // reported. + uint8_t preferred_index = 0; + for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { + if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { + preferred_index = i; + } + } + return preferred_index; +} + +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status) +{ + JNIEnv *e; + NFCSTATUS ret; + jclass tag_cls = NULL; + jobject target_array; + jobject tag; + jmethodID ctor; + jfieldID f; + const char * typeName; + jbyteArray tagUid; + jbyteArray generalBytes = NULL; + struct nfc_jni_native_data *nat; + struct timespec ts; + phNfc_sData_t data; + int i; + int target_index = 0; // Target that will be reported (if multiple can be >0) + + nat = (struct nfc_jni_native_data *)pContext; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); + + /* Notify manager that a target was deselected */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); + TRACE("Discovered %d tags", uNofRemoteDev); + + target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); + + /* Reset device connected flag */ + device_connected_flag = 1; + phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; + phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + + tag_cls = e->GetObjectClass(nat->cached_P2pDevice); + if(e->ExceptionCheck()) + { + ALOGE("Get Object Class Error"); + kill_client(nat); + return; + } + + /* New target instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID(tag_cls, "mMode", "I"); + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + ALOGD("Discovered P2P Initiator"); + e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); + } + else + { + ALOGD("Discovered P2P Target"); + e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); + } + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + /* Set General Bytes */ + f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes length ="); + for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) + { + ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); + } + + generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + + e->SetByteArrayRegion(generalBytes, 0, + remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, + (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); + + e->SetObjectField(tag, f, generalBytes); + } + + /* Set tag handle */ + f = e->GetFieldID(tag_cls, "mHandle", "I"); + e->SetIntField(tag, f,(jint)remDevHandle); + TRACE("Target handle = 0x%08x",remDevHandle); + } + else + { + tag_cls = e->GetObjectClass(nat->cached_NfcTag); + if(e->ExceptionCheck()) + { + kill_client(nat); + return; + } + + /* New tag instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + bool multi_protocol = false; + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + TRACE("Multiple Protocol TAG detected\n"); + multi_protocol = true; + } + + /* Set tag UID */ + f = e->GetFieldID(tag_cls, "mUid", "[B"); + data = get_target_uid(remDevInfo); + tagUid = e->NewByteArray(data.length); + if(data.length > 0) + { + e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); + } + e->SetObjectField(tag, f, tagUid); + + /* Generate technology list */ + jintArray techList; + jintArray handleList; + jintArray typeList; + nfc_jni_get_technology_tree(e, psRemoteDevList, + multi_protocol ? uNofRemoteDev : 1, + &techList, &handleList, &typeList); + + /* Push the technology list into the java object */ + f = e->GetFieldID(tag_cls, "mTechList", "[I"); + e->SetObjectField(tag, f, techList); + + f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); + e->SetObjectField(tag, f, handleList); + + f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField(tag, f, typeList); + + f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); + e->SetIntField(tag, f,(jint)-1); + + f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); + e->SetIntField(tag, f,(jint)-1); + } + + storedHandle = remDevHandle; + if (nat->tag != NULL) { + e->DeleteGlobalRef(nat->tag); + } + nat->tag = e->NewGlobalRef(tag); + + /* Notify the service */ + TRACE("Notify Nfc Service"); + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + /* Store the hanlde of the P2P device */ + hLlcpHandle = remDevHandle; + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + /* Notify manager that new a tag was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + e->DeleteLocalRef(tag); + } +} + +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_init_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_deinit_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Card Emulation callback */ +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) +{ + JNIEnv *e; + jobject tmp_array = NULL; + jobject mifare_block = NULL; + struct nfc_jni_native_data *nat; + phNfc_sData_t *aid; + phNfc_sData_t *mifare_command; + struct nfc_jni_callback_data *pCallbackData; + int i=0; + + LOG_CALLBACK("nfc_jni_transaction_callback", status); + + nat = (struct nfc_jni_native_data *)context; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_SUCCESS) + { + switch(evt_type) + { + case phLibNfc_eSE_EvtStartTransaction: + { + TRACE("> SE EVT_START_TRANSACTION"); + if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) + { + aid = &(evt_info->UiccEvtInfo.aid); + + ALOGD("> AID DETECTED"); + + if(aid != NULL) + { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + ALOGD("> AID: %s", aid_str); + + tmp_array = e->NewByteArray(aid->length); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + goto error; + } + + TRACE("Notify Nfc Service"); + /* Notify manager that a new event occurred on a SE */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + ALOGD("> NO AID DETECTED"); + } + }break; + + case phLibNfc_eSE_EvtApduReceived: + { + phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); + TRACE("> SE EVT_APDU_RECEIVED"); + + if (apdu != NULL) { + TRACE(" APDU length=%d", apdu->length); + tmp_array = e->NewByteArray(apdu->length); + if (tmp_array == NULL) { + goto error; + } + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); + if (e->ExceptionCheck()) { + goto error; + } + } else { + TRACE(" APDU EMPTY"); + } + + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); + }break; + + case phLibNfc_eSE_EvtCardRemoval: + { + TRACE("> SE EVT_EMV_CARD_REMOVAL"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); + }break; + + case phLibNfc_eSE_EvtMifareAccess: + { + TRACE("> SE EVT_MIFARE_ACCESS"); + mifare_command = &(evt_info->UiccEvtInfo.aid); + TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); + tmp_array = e->NewByteArray(2); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); + }break; + + case phLibNfc_eSE_EvtFieldOn: + { + TRACE("> SE EVT_FIELD_ON"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); + }break; + + case phLibNfc_eSE_EvtFieldOff: + { + TRACE("> SE EVT_FIELD_OFF"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); + }break; + + default: + { + TRACE("Unknown SE event"); + }break; + } + } + else + { + ALOGE("SE transaction notification error"); + goto error; + } + + /* Function finished, now clean and return */ + goto clean_and_return; + + error: + /* In case of error, just discard the notification */ + ALOGE("Failed to send SE transaction notification"); + e->ExceptionClear(); + + clean_and_return: + if(tmp_array != NULL) + { + e->DeleteLocalRef(tmp_array); + } +} + +static void nfc_jni_se_set_mode_callback(void *pContext, + phLibNfc_Handle handle, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* + * NFCManager methods + */ + +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) +{ + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ + nfc_jni_reset_timeout_values(); + + /* Reload the p2p modes */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Start Polling loop */ + TRACE("****** Start NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, + nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + +static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) +{ + phLibNfc_sADD_Cfg_t discovery_cfg; + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + discovery_cfg.PollDevInfo.PollEnabled = 0; + discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; + discovery_cfg.NfcIP_Target_Mode = 0; + discovery_cfg.NfcIP_Tgt_Disable = TRUE; + + /* Start Polling loop */ + TRACE("****** Stop NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nfc_jni_stop_discovery_locked(nat); + + CONCURRENCY_UNLOCK(); + +} + +static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + nat = nfc_jni_get_nat(e, o); + + /* Register callback for remote device notifications. + * Must re-register every time we turn on discovery, since other operations + * (such as opening the Secure Element) can change the remote device + * notification callback*/ + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", + nat->registry_info.Jewel==TRUE?"J":"", + nat->registry_info.MifareUL==TRUE?"UL":"", + nat->registry_info.MifareStd==TRUE?"Mi":"", + nat->registry_info.Felica==TRUE?"F":"", + nat->registry_info.ISO14443_4A==TRUE?"4A":"", + nat->registry_info.ISO14443_4B==TRUE?"4B":"", + nat->registry_info.NFC==TRUE?"P2P":"", + nat->registry_info.ISO15693==TRUE?"R":"", ret); + + nfc_jni_start_discovery_locked(nat, false); +clean_and_return: + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { + CONCURRENCY_LOCK(); + nfc_jni_reset_timeout_values(); + CONCURRENCY_UNLOCK(); +} + +static void setFelicaTimeout(jint timeout) { + // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. + // It can be set to 0 to disable the timeout altogether, in which case we + // use the sw watchdog as a fallback. + if (timeout <= 255) { + phLibNfc_SetFelicaTimeout(timeout); + } else { + // Disable hw timeout, use sw watchdog for timeout + phLibNfc_SetFelicaTimeout(0); + phLibNfc_SetHciTimeout(timeout); + } + +} +// Calculates ceiling log2 of value +static unsigned int log2(int value) { + unsigned int ret = 0; + bool isPowerOf2 = ((value & (value - 1)) == 0); + while ( (value >> ret) > 1 ) ret++; + if (!isPowerOf2) ret++; + return ret; +} + +// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X +// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X +// +// We keep the constant part of the formula in a static; note the factor +// 1000 off, which is due to the fact that the formula calculates seconds, +// but this method gets milliseconds as an argument. +static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; + +static int calcTimeout(int timeout_in_ms) { + // timeout = (256 * 16 / 13560000) * 2 ^ X + // First find the first X for which timeout > requested timeout + return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); +} + +static void setIsoDepTimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + // Then re-compute the actual timeout based on X + double actual_timeout = nxp_nfc_timeout_factor * (1 << value); + // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, + // but it will take some time to get back through the sw layers. + // 500 ms should be enough). + phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); + value |= 0x10; // bit 4 to enable timeout + phLibNfc_SetIsoXchgTimeout(value); + } + else { + // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout + // must be disabled completely, to prevent the PN544 from aborting + // the transaction. We reuse the HCI sw watchdog to catch the timeout + // in that case. + phLibNfc_SetIsoXchgTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static void setNfcATimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + phLibNfc_SetMifareRawTimeout(value); + } + else { + // Disable mifare raw timeout, use HCI sw watchdog instead + phLibNfc_SetMifareRawTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, + jint tech, jint timeout) { + bool success = false; + CONCURRENCY_LOCK(); + if (timeout <= 0) { + ALOGE("Timeout must be positive."); + return false; + } else { + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + setNfcATimeout(timeout); + success = true; + break; + case TARGET_TYPE_ISO14443_4: + setIsoDepTimeout(timeout); + success = true; + break; + case TARGET_TYPE_FELICA: + setFelicaTimeout(timeout); + success = true; + break; + default: + ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); + success = false; + } + } + CONCURRENCY_UNLOCK(); + return success; +} + +static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, + jint tech) { + int timeout = -1; + CONCURRENCY_LOCK(); + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + timeout = phLibNfc_GetMifareRawTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_ISO14443_4: + timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_FELICA: + timeout = phLibNfc_GetFelicaTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Felica timeout already in ms + } + break; + default: + ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); + break; + } + CONCURRENCY_UNLOCK(); + return timeout; +} + + +static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct nfc_jni_native_data *nat = NULL; + jclass cls; + jobject obj; + jfieldID f; + + TRACE("****** Init Native Structure ******"); + + /* Initialize native structure */ + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if(nat == NULL) + { + ALOGD("malloc of nfc_jni_native_data failed"); + return FALSE; + } + memset(nat, 0, sizeof(*nat)); + e->GetJavaVM(&(nat->vm)); + nat->env_version = e->GetVersion(); + nat->manager = e->NewGlobalRef(o); + + cls = e->GetObjectClass(o); + f = e->GetFieldID(cls, "mNative", "I"); + e->SetIntField(o, f, (jint)nat); + + /* Initialize native cached references */ + cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, + "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, + "notifyTargetDeselected","()V"); + + cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, + "notifySeFieldActivated", "()V"); + + cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, + "notifySeFieldDeactivated", "()V"); + + cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + TRACE("****** Init Native Structure OK ******"); + return TRUE; + +} + +/* Init/Deinit method */ +static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + int init_result = JNI_FALSE; +#ifdef TNFC_EMULATOR_ONLY + char value[PROPERTY_VALUE_MAX]; +#endif + jboolean result; + + CONCURRENCY_LOCK(); + +#ifdef TNFC_EMULATOR_ONLY + if (!property_get("ro.kernel.qemu", value, 0)) + { + ALOGE("NFC Initialization failed: not running in an emulator\n"); + goto clean_and_return; + } +#endif + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nat->seId = SMX_SECURE_ELEMENT_ID; + + nat->lto = 150; // LLCP_LTO + nat->miu = 128; // LLCP_MIU + // WKS indicates well-known services; 1 << sap for each supported SAP. + // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) + nat->wks = 0x13; // LLCP_WKS + nat->opt = 0; // LLCP_OPT + nat->p2p_initiator_modes = phNfc_eP2P_ALL; + nat->p2p_target_modes = 0x0E; // All passive except 106, active + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; + + nat->registry_info.MifareUL = TRUE; + nat->registry_info.MifareStd = TRUE; + nat->registry_info.ISO14443_4A = TRUE; + nat->registry_info.ISO14443_4B = TRUE; + nat->registry_info.Jewel = TRUE; + nat->registry_info.Felica = TRUE; + nat->registry_info.NFC = TRUE; + nat->registry_info.ISO15693 = TRUE; + + exported_nat = nat; + + /* Perform the initialization */ + init_result = nfc_jni_initialize(nat); + +clean_and_return: + CONCURRENCY_UNLOCK(); + + /* Convert the result and return */ + return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; +} + +static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) +{ + struct timespec ts; + NFCSTATUS status; + int result = JNI_FALSE; + struct nfc_jni_native_data *nat; + int bStackReset = FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Clear previous configuration */ + memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); + memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); + + /* Create the local semaphore */ + if (nfc_cb_data_init(&cb_data, NULL)) + { + TRACE("phLibNfc_Mgt_DeInitialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status == NFCSTATUS_PENDING) + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts) == -1) + { + ALOGW("Operation timed out"); + bStackReset = TRUE; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Failed to deinit the stack"); + bStackReset = TRUE; + } + } + else + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + bStackReset = TRUE; + } + nfc_cb_data_deinit(&cb_data); + } + else + { + ALOGE("Failed to create semaphore (errno=0x%08x)", errno); + bStackReset = TRUE; + } + + kill_client(nat); + + if(bStackReset == TRUE) + { + /* Complete deinit. failed, try hard restart of NFC */ + ALOGW("Reseting stack..."); + emergency_recovery(nat); + } + + result = nfc_jni_unconfigure_driver(nat); + + TRACE("NFC Deinitialized"); + + CONCURRENCY_UNLOCK(); + + return TRUE; +} + +/* Secure Element methods */ +static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { + NFCSTATUS ret; + jintArray list= NULL; + phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; + + TRACE("****** Get Secure Element List ******"); + + TRACE("phLibNfc_SE_GetSecureElementList()"); + REENTRANCE_LOCK(); + ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_SUCCESS) { + ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + return list; + } + TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + + TRACE("Nb SE: %d", se_count); + list =e->NewIntArray(se_count); + for (i = 0; i < se_count; i++) { + if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } + e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); + } + + e->DeleteLocalRef(list); + + return list; +} + +static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Select Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Virtual */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING) { + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Deselect Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Default */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, + nfc_jni_se_set_mode_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); + if (ret != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +/* Llcp methods */ + +static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + bool freeData = false; + jboolean result = JNI_FALSE; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data *cb_data; + + + CONCURRENCY_LOCK(); + + /* Memory allocation for cb_data + * This is on the heap because it is used by libnfc + * even after this call has succesfully finished. It is only freed + * upon link closure in nfc_jni_llcp_linkStatus_callback. + */ + cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(cb_data, (void*)nat)) + { + goto clean_and_return; + } + + /* Check LLCP compliancy */ + TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, + nfc_jni_checkLlcp_callback, + nfc_jni_llcp_linkStatus_callback, + (void*)cb_data); + REENTRANCE_UNLOCK(); + /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol + * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + freeData = true; + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data->sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data->status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(cb_data); + if (freeData) { + free(cb_data); + } + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Activate(hLlcpHandle); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_FALSE; + } +} + + + +static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, + jint nSap, jstring sn) +{ + NFCSTATUS ret; + jobject connectionlessSocket = NULL; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_native_data *nat; + phNfc_sData_t sWorkingBuffer = {NULL, 0}; + phNfc_sData_t serviceName = {NULL, 0}; + phLibNfc_Llcp_sLinkParameters_t sParams; + jclass clsNativeConnectionlessSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Allocate Working buffer length */ + phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); + sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, + NULL, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + + /* Create new NativeLlcpConnectionlessSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + { + goto error; + } + + /* Get NativeConnectionless class object */ + clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); + if(e->ExceptionCheck()) + { + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); + e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); + TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); + + /* Set the miu link of the connectionless socket */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); + e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); + TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); + e->SetIntField(connectionlessSocket, f,(jint)nSap); + TRACE("Connectionless socket SAP = %d\n",nSap); + + return connectionlessSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + + if (sWorkingBuffer.buffer != NULL) { + free(sWorkingBuffer.buffer); + } + + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + phNfc_sData_t serviceName; + struct nfc_jni_native_data *nat; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + ret = phLibNfc_Llcp_Close(hLlcpSocket); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Listen( hLlcpSocket, + nfc_jni_llcp_transport_listen_socket_callback, + (void*)hLlcpSocket); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + /* Close created socket */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpServiceSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + { + ALOGE("Llcp Socket object creation error"); + goto error; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); + if(e->ExceptionCheck()) + { + ALOGE("Llcp Socket get object class error"); + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); + TRACE("Service socket Handle = %02x\n",hLlcpSocket); + + /* Set socket linear buffer length */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField(serviceSocket, f,(jint)linearBufferLength); + TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField(serviceSocket, f,(jint)miu); + TRACE("Service socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField(serviceSocket, f,(jint)rw); + TRACE("Service socket RW = %d\n",rw); + + return serviceSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + struct nfc_jni_native_data *nat; + jclass clsNativeLlcpSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + return NULL; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGE("Llcp socket object creation error"); + return NULL; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGE("Get class object error"); + return NULL; + } + + /* Test if an SAP number is present */ + if(nSap != 0) + { + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + return NULL; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField(clientSocket, f,(jint)nSap); + TRACE("socket SAP = %d\n",nSap); + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hLlcpSocket); + TRACE("socket Handle = %02x\n",hLlcpSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + TRACE("socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + TRACE("socket RW = %d\n",rw); + + + return clientSocket; +} + +static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) +{ + TRACE("Last Error Status = 0x%02x",lastErrorStatus); + + if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) + { + return ERROR_BUFFER_TOO_SMALL; + } + else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) + { + return ERROR_INSUFFICIENT_RESOURCES; + } + else + { + return lastErrorStatus; + } +} + +static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) +{ + emergency_recovery(NULL); +} + +static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting init modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_initiator_modes = modes; +} + +static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting target modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_target_modes = modes; +} + +static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { + bool result = FALSE; + int load_result; + bool wasDisabled = FALSE; + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + NFCSTATUS status = NFCSTATUS_FAILED; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + result = FALSE; + goto clean_and_return; + } + + if (takeLock) + { + CONCURRENCY_LOCK(); + } + + /* Initialize Driver */ + if(!driverConfigured) + { + result = nfc_jni_configure_driver(nat); + wasDisabled = TRUE; + } + TRACE("com_android_nfc_NfcManager_doDownload()"); + + TRACE("Go in Download Mode"); + phLibNfc_Download_Mode(); + + TRACE("Load new Firmware Image"); + load_result = phLibNfc_Load_Firmware_Image(); + if(load_result != 0) + { + TRACE("Load new Firmware Image - status = %d",load_result); + result = FALSE; + goto clean_and_return; + } + + // Download + gInputParam.buffer = InputBuffer; + gInputParam.length = 0x01; + gOutputParam.buffer = OutputBuffer; + gOutputParam.length = 0x01; + + ALOGD("Download new Firmware"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + result = FALSE; + goto clean_and_return; + } + + /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we + try to download an old-style firmware on top of a new-style + firmware. Hence, this is expected behavior, and not an + error condition. */ + if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); + } + + /*Download is successful*/ + result = TRUE; +clean_and_return: + TRACE("phLibNfc_HW_Reset()"); + phLibNfc_HW_Reset(); + /* Deinitialize Driver */ + if(wasDisabled) + { + result = nfc_jni_unconfigure_driver(nat); + } + if (takeLock) + { + CONCURRENCY_UNLOCK(); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + return performDownload(nat, true); +} + +static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); + return e->NewStringUTF(buffer); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)com_android_nfc_NfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void *)com_android_nfc_NfcManager_init_native_struc}, + + {"doInitialize", "()Z", + (void *)com_android_nfc_NfcManager_initialize}, + + {"doDeinitialize", "()Z", + (void *)com_android_nfc_NfcManager_deinitialize}, + + {"enableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)com_android_nfc_NfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)com_android_nfc_NfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)com_android_nfc_NfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)com_android_nfc_NfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)com_android_nfc_NfcManager_doAbort}, + + {"doSetP2pInitiatorModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)com_android_nfc_NfcManager_doDump}, +}; + + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e) +{ + nfc_jni_native_monitor_t *nfc_jni_native_monitor; + + nfc_jni_native_monitor = nfc_jni_init_monitor(); + if(nfc_jni_native_monitor == NULL) + { + ALOGE("NFC Manager cannot recover native monitor %x\n", errno); + return -1; + } + + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; iRemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;iNewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..f969627 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eddde94 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 602b25d..3e7a6b5 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.nxp.NativeNfcManager; -import com.android.nfc.nxp.NativeNfcSecureElement; +import com.android.nfc.dhimpl.NativeNfcManager; +import com.android.nfc.dhimpl.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; diff --git a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index c9d3b5d..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java deleted file mode 100755 index 531afd8..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java deleted file mode 100755 index a337d35..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java deleted file mode 100755 index 4bd8c24..0000000 --- a/src/com/android/nfc/nxp/NativeNfcManager.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java deleted file mode 100755 index 88f9b9d..0000000 --- a/src/com/android/nfc/nxp/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java deleted file mode 100755 index 8996dfb..0000000 --- a/src/com/android/nfc/nxp/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java deleted file mode 100755 index 7c7db41..0000000 --- a/src/com/android/nfc/nxp/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} -- cgit v1.1 From 51a43593261ebf190f736ecbb3939b69479a21dc Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 24 Jul 2012 20:54:28 -0700 Subject: Revert "Move NXP JNI and DeviceHost implementation into separate dir." (DO NOT MERGE) This reverts commit 26f6049196acaa9768ba6bdef343216ea878a4c1. Change-Id: I7ed3a1ba24bbbdb3336547c20f47c344d70b2d30 --- Android.mk | 8 - jni/Android.mk | 35 + jni/com_android_nfc.cpp | 564 +++++ jni/com_android_nfc.h | 259 ++ ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 ++ jni/com_android_nfc_NativeLlcpServiceSocket.cpp | 227 ++ jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ++++ jni/com_android_nfc_NativeNfcManager.cpp | 2622 ++++++++++++++++++++ jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ++++++ jni/com_android_nfc_NativeNfcTag.cpp | 1255 ++++++++++ jni/com_android_nfc_NativeP2pDevice.cpp | 490 ++++ jni/com_android_nfc_list.cpp | 210 ++ jni/com_android_nfc_list.h | 49 + nxp/jni/Android.mk | 35 - nxp/jni/com_android_nfc.cpp | 564 ----- nxp/jni/com_android_nfc.h | 259 -- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 -- .../com_android_nfc_NativeLlcpServiceSocket.cpp | 227 -- nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ---- nxp/jni/com_android_nfc_NativeNfcManager.cpp | 2622 -------------------- nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ------ nxp/jni/com_android_nfc_NativeNfcTag.cpp | 1255 ---------- nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 490 ---- nxp/jni/com_android_nfc_list.cpp | 210 -- nxp/jni/com_android_nfc_list.h | 49 - .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 - .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 - .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 - .../com/android/nfc/dhimpl/NativeNfcManager.java | 373 --- .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 - nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 803 ------ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 - src/com/android/nfc/NfcService.java | 4 +- .../nfc/nxp/NativeLlcpConnectionlessSocket.java | 78 + .../android/nfc/nxp/NativeLlcpServiceSocket.java | 53 + src/com/android/nfc/nxp/NativeLlcpSocket.java | 99 + src/com/android/nfc/nxp/NativeNfcManager.java | 373 +++ .../android/nfc/nxp/NativeNfcSecureElement.java | 67 + src/com/android/nfc/nxp/NativeNfcTag.java | 803 ++++++ src/com/android/nfc/nxp/NativeP2pDevice.java | 77 + 40 files changed, 8754 insertions(+), 8762 deletions(-) create mode 100644 jni/Android.mk create mode 100644 jni/com_android_nfc.cpp create mode 100644 jni/com_android_nfc.h create mode 100644 jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp create mode 100644 jni/com_android_nfc_NativeLlcpServiceSocket.cpp create mode 100644 jni/com_android_nfc_NativeLlcpSocket.cpp create mode 100644 jni/com_android_nfc_NativeNfcManager.cpp create mode 100755 jni/com_android_nfc_NativeNfcSecureElement.cpp create mode 100644 jni/com_android_nfc_NativeNfcTag.cpp create mode 100644 jni/com_android_nfc_NativeP2pDevice.cpp create mode 100644 jni/com_android_nfc_list.cpp create mode 100644 jni/com_android_nfc_list.h delete mode 100644 nxp/jni/Android.mk delete mode 100644 nxp/jni/com_android_nfc.cpp delete mode 100644 nxp/jni/com_android_nfc.h delete mode 100644 nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeLlcpSocket.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeNfcManager.cpp delete mode 100755 nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeNfcTag.cpp delete mode 100644 nxp/jni/com_android_nfc_NativeP2pDevice.cpp delete mode 100644 nxp/jni/com_android_nfc_list.cpp delete mode 100644 nxp/jni/com_android_nfc_list.h delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java delete mode 100755 nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java create mode 100755 src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java create mode 100755 src/com/android/nfc/nxp/NativeLlcpServiceSocket.java create mode 100755 src/com/android/nfc/nxp/NativeLlcpSocket.java create mode 100755 src/com/android/nfc/nxp/NativeNfcManager.java create mode 100755 src/com/android/nfc/nxp/NativeNfcSecureElement.java create mode 100755 src/com/android/nfc/nxp/NativeNfcTag.java create mode 100755 src/com/android/nfc/nxp/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index 2cdfc68..a041854 100644 --- a/Android.mk +++ b/Android.mk @@ -6,14 +6,6 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) -ifeq ($(NFC_USE_NCI_STACK), true) - LOCAL_SRC_FILES += \ - $(call all-java-files-under, nci) -else - LOCAL_SRC_FILES += \ - $(call all-java-files-under, nxp) -endif - LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h new file mode 100644 index 0000000..a44bcf0 --- /dev/null +++ b/jni/com_android_nfc.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include +#include + +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#else + #define LOG_CALLBACK(...) + #define TRACE(...) +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeLlcpSocket.cpp b/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..704ee6a --- /dev/null +++ b/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2622 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "com_android_nfc.h" + +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +extern uint32_t libnfc_llc_error_count; + +static phLibNfc_sConfig_t gDrvCfg; +void *gHWRef; +static phNfc_sData_t gInputParam; +static phNfc_sData_t gOutputParam; + +uint8_t device_connected_flag; +static bool driverConfigured = FALSE; + +static phLibNfc_Handle hLlcpHandle; +static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; +static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; + +static jmethodID cached_NfcManager_notifyNdefMessageListeners; +static jmethodID cached_NfcManager_notifyTransactionListeners; +static jmethodID cached_NfcManager_notifyLlcpLinkActivation; +static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; +static jmethodID cached_NfcManager_notifyTargetDeselected; + +static jmethodID cached_NfcManager_notifySeFieldActivated; +static jmethodID cached_NfcManager_notifySeFieldDeactivated; + +static jmethodID cached_NfcManager_notifySeApduReceived; +static jmethodID cached_NfcManager_notifySeMifareAccess; +static jmethodID cached_NfcManager_notifySeEmvCardRemoval; + +namespace android { + +phLibNfc_Handle storedHandle = 0; + +struct nfc_jni_native_data *exported_nat = NULL; + +/* Internal functions declaration */ +static void *nfc_jni_client_thread(void *arg); +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_se_set_mode_callback(void *context, + phLibNfc_Handle handle, NFCSTATUS status); +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status); +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); +static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); + +/* + * Deferred callback called when client thread must be exited + */ +static void client_kill_deferred_call(void* arg) +{ + struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; + + nat->running = FALSE; +} + +static void kill_client(nfc_jni_native_data *nat) +{ + phDal4Nfc_Message_Wrapper_t wrapper; + phLibNfc_DeferredCall_t *pMsg; + + usleep(50000); + + ALOGD("Terminating client thread..."); + + pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); + pMsg->pCallback = client_kill_deferred_call; + pMsg->pParameter = (void*)nat; + + wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + wrapper.msg.pMsgData = pMsg; + wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); + + phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); +} + +static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_ioctl_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_deinit_download_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) +{ + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + struct timespec ts; + NFCSTATUS status = NFCSTATUS_FAILED; + phLibNfc_StackCapabilities_t caps; + struct nfc_jni_callback_data cb_data; + bool result; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + if(update) + { + //deinit + TRACE("phLibNfc_Mgt_DeInitialize() (download)"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts)) + { + ALOGW("Deinitialization timed out (download)"); + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("Deinitialization FAILED (download)"); + } + TRACE("Deinitialization SUCCESS (download)"); + } + + result = performDownload(nat, false); + + if (!result) { + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + status = cb_data.status; + goto clean_and_return; + } + + /* ====== CAPABILITIES ======= */ + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /*Download is successful*/ + status = NFCSTATUS_SUCCESS; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return status; +} + +static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) +{ + char value[PROPERTY_VALUE_MAX]; + int result = FALSE; + NFCSTATUS status; + + /* ====== CONFIGURE DRIVER ======= */ + /* Configure hardware link */ + gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); + + TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); + REENTRANCE_UNLOCK(); + if(status == NFCSTATUS_ALREADY_INITIALISED) { + ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) + { + ALOGE("pthread_create failed"); + goto clean_and_return; + } + + driverConfigured = TRUE; + +clean_and_return: + return result; +} + +static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) +{ + int result = FALSE; + NFCSTATUS status; + + /* Unconfigure driver */ + TRACE("phLibNfc_Mgt_UnConfigureDriver()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); + } + else + { + ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = TRUE; + } + + driverConfigured = FALSE; + + return result; +} + +/* Initialization function */ +static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { + struct timespec ts; + uint8_t resp[16]; + NFCSTATUS status; + phLibNfc_StackCapabilities_t caps; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; + phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; + struct nfc_jni_callback_data cb_data; + uint8_t firmware_status; + uint8_t update = TRUE; + int result = JNI_FALSE; + const hw_module_t* hw_module; + nfc_pn544_device_t* pn544_dev = NULL; + int ret = 0; + ALOGD("Start Initialization\n"); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Get EEPROM values and device port from product-specific settings */ + ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); + if (ret) { + ALOGE("hw_get_module() failed."); + goto clean_and_return; + } + ret = nfc_pn544_open(hw_module, &pn544_dev); + if (ret) { + ALOGE("Could not open pn544 hw_module."); + goto clean_and_return; + } + if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { + ALOGE("Could not load EEPROM settings"); + goto clean_and_return; + } + + /* Reset device connected handle */ + device_connected_flag = 0; + + /* Reset stored handle */ + storedHandle = 0; + + /* Initialize Driver */ + if(!driverConfigured) + { + nfc_jni_configure_driver(nat); + } + + /* ====== INITIALIZE ======= */ + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + update = FALSE; + goto force_download; + } + TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + update = FALSE; + goto force_download; + } + + /* ====== CAPABILITIES ======= */ + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /* ====== FIRMWARE VERSION ======= */ + if(caps.psDevCapabilities.firmware_update_info) + { +force_download: + for (i=0; i<3; i++) + { + TRACE("Firmware version not UpToDate"); + status = nfc_jni_download_locked(nat, update); + if(status == NFCSTATUS_SUCCESS) + { + ALOGI("Firmware update SUCCESS"); + break; + } + ALOGW("Firmware update FAILED"); + update = FALSE; + } + if(i>=3) + { + ALOGE("Unable to update firmware, giving up"); + goto clean_and_return; + } + } + else + { + TRACE("Firmware version UpToDate"); + } + /* ====== EEPROM SETTINGS ======= */ + + // Update EEPROM settings + TRACE("****** START EEPROM SETTINGS UPDATE ******"); + for (i = 0; i < pn544_dev->num_eeprom_settings; i++) + { + char eeprom_property[PROPERTY_KEY_MAX]; + char eeprom_value[PROPERTY_VALUE_MAX]; + uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); + TRACE("> EEPROM SETTING: %d", i); + + // Check for override of this EEPROM value in properties + snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", + eeprom_base[1], eeprom_base[2]); + TRACE(">> Checking property: %s", eeprom_property); + if (property_get(eeprom_property, eeprom_value, "") == 2) { + int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); + ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", + eeprom_base[1], eeprom_base[2], eeprom_value_num); + eeprom_base[3] = eeprom_value_num; + } + + TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], + eeprom_base[3]); + gInputParam.buffer = eeprom_base; + gInputParam.length = 0x04; + gOutputParam.buffer = resp; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if (cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + } + TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); + + /* ====== SECURE ELEMENTS ======= */ + + REENTRANCE_LOCK(); + ALOGD("phLibNfc_SE_GetSecureElementList()"); + status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + + ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i < No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); + } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); + } + + /* Set SE mode - Off */ + REENTRANCE_LOCK(); + status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, + phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + } + + /* ====== LLCP ======= */ + + /* LLCP Params */ + TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); + LlcpConfigInfo.miu = nat->miu; + LlcpConfigInfo.lto = nat->lto; + LlcpConfigInfo.wks = nat->wks; + LlcpConfigInfo.option = nat->opt; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, + nfc_jni_llcpcfg_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* ===== DISCOVERY ==== */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.Duration = 300000; /* in ms */ + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== END ======= */ + + ALOGI("NFC Initialized"); + + result = TRUE; + +clean_and_return: + if (result != TRUE) + { + if(nat) + { + kill_client(nat); + } + } + if (pn544_dev != NULL) { + nfc_pn544_close(pn544_dev); + } + nfc_cb_data_deinit(&cb_data); + + return result; +} + +static int is_user_build() { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", value, ""); + return !strncmp("user", value, PROPERTY_VALUE_MAX); +} + +/* + * Last-chance fallback when there is no clean way to recover + * Performs a software reset + */ +void emergency_recovery(struct nfc_jni_native_data *nat) { + if (!is_user_build()) { + ALOGE("emergency_recovery: force restart of NFC service"); + } else { + // dont recover immediately, so we can debug + unsigned int t; + for (t=1; t < 1000000; t <<= 1) { + ALOGE("emergency_recovery: NFC stack dead-locked"); + sleep(t); + } + } + phLibNfc_Mgt_Recovery(); + abort(); // force a noisy crash +} + +void nfc_jni_reset_timeout_values() +{ + REENTRANCE_LOCK(); + phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); + phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); + phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); + phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); + REENTRANCE_UNLOCK(); +} + +/* + * Restart the polling loop when unable to perform disconnect + */ +void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) +{ + nfc_jni_start_discovery_locked(nat, true); +} + + /* + * Utility to recover UID from target infos + */ +static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + phNfc_sData_t uid; + + switch(psRemoteDevInfo->RemDevType) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_3A_PICC: + case phNfc_eMifare_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; + break; + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; + uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); + break; + case phNfc_eFelica_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; + uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; + break; + case phNfc_eJewel_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; + break; + case phNfc_eISO15693_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; + break; + case phNfc_eNfcIP1_Target: + case phNfc_eNfcIP1_Initiator: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; + uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; + break; + default: + uid.buffer = NULL; + uid.length = 0; + break; + } + + return uid; +} + +/* + * NFC stack message processing + */ +static void *nfc_jni_client_thread(void *arg) +{ + struct nfc_jni_native_data *nat; + JNIEnv *e; + JavaVMAttachArgs thread_args; + phDal4Nfc_Message_Wrapper_t wrapper; + + nat = (struct nfc_jni_native_data *)arg; + + thread_args.name = "NFC Message Loop"; + thread_args.version = nat->env_version; + thread_args.group = NULL; + + nat->vm->AttachCurrentThread(&e, &thread_args); + pthread_setname_np(pthread_self(), "message"); + + TRACE("NFC client started"); + nat->running = TRUE; + while(nat->running == TRUE) + { + /* Fetch next message from the NFC stack message queue */ + if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, + sizeof(phLibNfc_Message_t), 0, 0) == -1) + { + ALOGE("NFC client received bad message"); + continue; + } + + switch(wrapper.msg.eMsgType) + { + case PH_LIBNFC_DEFERREDCALL_MSG: + { + phLibNfc_DeferredCall_t *msg = + (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); + + REENTRANCE_LOCK(); + msg->pCallback(msg->pParameter); + REENTRANCE_UNLOCK(); + + break; + } + } + } + TRACE("NFC client stopped"); + + nat->vm->DetachCurrentThread(); + + return NULL; +} + +extern uint8_t nfc_jni_is_ndef; +extern uint8_t *nfc_jni_ndef_buf; +extern uint32_t nfc_jni_ndef_buf_len; + +static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = +{ + 3, + { 0x46, 0x66, 0x6D } +}; + +/* + * Callbacks + */ + +/* P2P - LLCP callbacks */ +static void nfc_jni_llcp_linkStatus_callback(void *pContext, + phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) +{ + phFriNfc_Llcp_sLinkParameters_t sLinkParams; + JNIEnv *e; + NFCSTATUS status; + + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; + + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + /* Update link status */ + g_eLinkStatus = eLinkStatus; + + if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) + { + REENTRANCE_LOCK(); + status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGW("GetRemote Info failded - Status = %02x",status); + } + else + { + ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, + sLinkParams.miu, + sLinkParams.option, + sLinkParams.wks); + device_connected_flag = 1; + } + } + else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) + { + ALOGI("LLCP Link deactivated"); + free(pContextData); + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Reset incoming socket list */ + while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) + { + pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); + LIST_REMOVE(pListenData, entries); + free(pListenData); + } + + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } +} + +static void nfc_jni_checkLlcp_callback(void *context, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; + + LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, + phLibNfc_Handle hIncomingSocket) +{ + phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + + /* Store the connection request */ + pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); + if (pListenData == NULL) + { + ALOGE("Failed to create structure to handle incoming LLCP connection request"); + goto clean_and_return; + } + pListenData->pServerSocket = hServiceSocket; + pListenData->pIncomingSocket = hIncomingSocket; + LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); + + /* Signal pending accept operations that the list is updated */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + +clean_and_return: + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); +} + +void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode) +{ + PHNFC_UNUSED_VARIABLE(pContext); + + TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); + + if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) + { + ALOGW("Frame Rejected - Disconnected"); + } + else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) + { + ALOGD("Socket Disconnected"); + } +} + + +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_discover_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNoOfRemoteDev) +{ + // Always prefer p2p targets over other targets. Otherwise, select the first target + // reported. + uint8_t preferred_index = 0; + for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { + if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { + preferred_index = i; + } + } + return preferred_index; +} + +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status) +{ + JNIEnv *e; + NFCSTATUS ret; + jclass tag_cls = NULL; + jobject target_array; + jobject tag; + jmethodID ctor; + jfieldID f; + const char * typeName; + jbyteArray tagUid; + jbyteArray generalBytes = NULL; + struct nfc_jni_native_data *nat; + struct timespec ts; + phNfc_sData_t data; + int i; + int target_index = 0; // Target that will be reported (if multiple can be >0) + + nat = (struct nfc_jni_native_data *)pContext; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); + + /* Notify manager that a target was deselected */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); + TRACE("Discovered %d tags", uNofRemoteDev); + + target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); + + /* Reset device connected flag */ + device_connected_flag = 1; + phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; + phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + + tag_cls = e->GetObjectClass(nat->cached_P2pDevice); + if(e->ExceptionCheck()) + { + ALOGE("Get Object Class Error"); + kill_client(nat); + return; + } + + /* New target instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID(tag_cls, "mMode", "I"); + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + ALOGD("Discovered P2P Initiator"); + e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); + } + else + { + ALOGD("Discovered P2P Target"); + e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); + } + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + /* Set General Bytes */ + f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes length ="); + for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) + { + ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); + } + + generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + + e->SetByteArrayRegion(generalBytes, 0, + remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, + (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); + + e->SetObjectField(tag, f, generalBytes); + } + + /* Set tag handle */ + f = e->GetFieldID(tag_cls, "mHandle", "I"); + e->SetIntField(tag, f,(jint)remDevHandle); + TRACE("Target handle = 0x%08x",remDevHandle); + } + else + { + tag_cls = e->GetObjectClass(nat->cached_NfcTag); + if(e->ExceptionCheck()) + { + kill_client(nat); + return; + } + + /* New tag instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + bool multi_protocol = false; + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + TRACE("Multiple Protocol TAG detected\n"); + multi_protocol = true; + } + + /* Set tag UID */ + f = e->GetFieldID(tag_cls, "mUid", "[B"); + data = get_target_uid(remDevInfo); + tagUid = e->NewByteArray(data.length); + if(data.length > 0) + { + e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); + } + e->SetObjectField(tag, f, tagUid); + + /* Generate technology list */ + jintArray techList; + jintArray handleList; + jintArray typeList; + nfc_jni_get_technology_tree(e, psRemoteDevList, + multi_protocol ? uNofRemoteDev : 1, + &techList, &handleList, &typeList); + + /* Push the technology list into the java object */ + f = e->GetFieldID(tag_cls, "mTechList", "[I"); + e->SetObjectField(tag, f, techList); + + f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); + e->SetObjectField(tag, f, handleList); + + f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField(tag, f, typeList); + + f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); + e->SetIntField(tag, f,(jint)-1); + + f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); + e->SetIntField(tag, f,(jint)-1); + } + + storedHandle = remDevHandle; + if (nat->tag != NULL) { + e->DeleteGlobalRef(nat->tag); + } + nat->tag = e->NewGlobalRef(tag); + + /* Notify the service */ + TRACE("Notify Nfc Service"); + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + /* Store the hanlde of the P2P device */ + hLlcpHandle = remDevHandle; + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + /* Notify manager that new a tag was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + e->DeleteLocalRef(tag); + } +} + +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_init_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_deinit_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Card Emulation callback */ +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) +{ + JNIEnv *e; + jobject tmp_array = NULL; + jobject mifare_block = NULL; + struct nfc_jni_native_data *nat; + phNfc_sData_t *aid; + phNfc_sData_t *mifare_command; + struct nfc_jni_callback_data *pCallbackData; + int i=0; + + LOG_CALLBACK("nfc_jni_transaction_callback", status); + + nat = (struct nfc_jni_native_data *)context; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_SUCCESS) + { + switch(evt_type) + { + case phLibNfc_eSE_EvtStartTransaction: + { + TRACE("> SE EVT_START_TRANSACTION"); + if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) + { + aid = &(evt_info->UiccEvtInfo.aid); + + ALOGD("> AID DETECTED"); + + if(aid != NULL) + { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + ALOGD("> AID: %s", aid_str); + + tmp_array = e->NewByteArray(aid->length); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + goto error; + } + + TRACE("Notify Nfc Service"); + /* Notify manager that a new event occurred on a SE */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + ALOGD("> NO AID DETECTED"); + } + }break; + + case phLibNfc_eSE_EvtApduReceived: + { + phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); + TRACE("> SE EVT_APDU_RECEIVED"); + + if (apdu != NULL) { + TRACE(" APDU length=%d", apdu->length); + tmp_array = e->NewByteArray(apdu->length); + if (tmp_array == NULL) { + goto error; + } + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); + if (e->ExceptionCheck()) { + goto error; + } + } else { + TRACE(" APDU EMPTY"); + } + + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); + }break; + + case phLibNfc_eSE_EvtCardRemoval: + { + TRACE("> SE EVT_EMV_CARD_REMOVAL"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); + }break; + + case phLibNfc_eSE_EvtMifareAccess: + { + TRACE("> SE EVT_MIFARE_ACCESS"); + mifare_command = &(evt_info->UiccEvtInfo.aid); + TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); + tmp_array = e->NewByteArray(2); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); + }break; + + case phLibNfc_eSE_EvtFieldOn: + { + TRACE("> SE EVT_FIELD_ON"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); + }break; + + case phLibNfc_eSE_EvtFieldOff: + { + TRACE("> SE EVT_FIELD_OFF"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); + }break; + + default: + { + TRACE("Unknown SE event"); + }break; + } + } + else + { + ALOGE("SE transaction notification error"); + goto error; + } + + /* Function finished, now clean and return */ + goto clean_and_return; + + error: + /* In case of error, just discard the notification */ + ALOGE("Failed to send SE transaction notification"); + e->ExceptionClear(); + + clean_and_return: + if(tmp_array != NULL) + { + e->DeleteLocalRef(tmp_array); + } +} + +static void nfc_jni_se_set_mode_callback(void *pContext, + phLibNfc_Handle handle, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* + * NFCManager methods + */ + +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) +{ + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ + nfc_jni_reset_timeout_values(); + + /* Reload the p2p modes */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Start Polling loop */ + TRACE("****** Start NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, + nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + +static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) +{ + phLibNfc_sADD_Cfg_t discovery_cfg; + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + discovery_cfg.PollDevInfo.PollEnabled = 0; + discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; + discovery_cfg.NfcIP_Target_Mode = 0; + discovery_cfg.NfcIP_Tgt_Disable = TRUE; + + /* Start Polling loop */ + TRACE("****** Stop NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nfc_jni_stop_discovery_locked(nat); + + CONCURRENCY_UNLOCK(); + +} + +static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + nat = nfc_jni_get_nat(e, o); + + /* Register callback for remote device notifications. + * Must re-register every time we turn on discovery, since other operations + * (such as opening the Secure Element) can change the remote device + * notification callback*/ + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", + nat->registry_info.Jewel==TRUE?"J":"", + nat->registry_info.MifareUL==TRUE?"UL":"", + nat->registry_info.MifareStd==TRUE?"Mi":"", + nat->registry_info.Felica==TRUE?"F":"", + nat->registry_info.ISO14443_4A==TRUE?"4A":"", + nat->registry_info.ISO14443_4B==TRUE?"4B":"", + nat->registry_info.NFC==TRUE?"P2P":"", + nat->registry_info.ISO15693==TRUE?"R":"", ret); + + nfc_jni_start_discovery_locked(nat, false); +clean_and_return: + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { + CONCURRENCY_LOCK(); + nfc_jni_reset_timeout_values(); + CONCURRENCY_UNLOCK(); +} + +static void setFelicaTimeout(jint timeout) { + // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. + // It can be set to 0 to disable the timeout altogether, in which case we + // use the sw watchdog as a fallback. + if (timeout <= 255) { + phLibNfc_SetFelicaTimeout(timeout); + } else { + // Disable hw timeout, use sw watchdog for timeout + phLibNfc_SetFelicaTimeout(0); + phLibNfc_SetHciTimeout(timeout); + } + +} +// Calculates ceiling log2 of value +static unsigned int log2(int value) { + unsigned int ret = 0; + bool isPowerOf2 = ((value & (value - 1)) == 0); + while ( (value >> ret) > 1 ) ret++; + if (!isPowerOf2) ret++; + return ret; +} + +// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X +// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X +// +// We keep the constant part of the formula in a static; note the factor +// 1000 off, which is due to the fact that the formula calculates seconds, +// but this method gets milliseconds as an argument. +static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; + +static int calcTimeout(int timeout_in_ms) { + // timeout = (256 * 16 / 13560000) * 2 ^ X + // First find the first X for which timeout > requested timeout + return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); +} + +static void setIsoDepTimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + // Then re-compute the actual timeout based on X + double actual_timeout = nxp_nfc_timeout_factor * (1 << value); + // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, + // but it will take some time to get back through the sw layers. + // 500 ms should be enough). + phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); + value |= 0x10; // bit 4 to enable timeout + phLibNfc_SetIsoXchgTimeout(value); + } + else { + // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout + // must be disabled completely, to prevent the PN544 from aborting + // the transaction. We reuse the HCI sw watchdog to catch the timeout + // in that case. + phLibNfc_SetIsoXchgTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static void setNfcATimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + phLibNfc_SetMifareRawTimeout(value); + } + else { + // Disable mifare raw timeout, use HCI sw watchdog instead + phLibNfc_SetMifareRawTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, + jint tech, jint timeout) { + bool success = false; + CONCURRENCY_LOCK(); + if (timeout <= 0) { + ALOGE("Timeout must be positive."); + return false; + } else { + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + setNfcATimeout(timeout); + success = true; + break; + case TARGET_TYPE_ISO14443_4: + setIsoDepTimeout(timeout); + success = true; + break; + case TARGET_TYPE_FELICA: + setFelicaTimeout(timeout); + success = true; + break; + default: + ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); + success = false; + } + } + CONCURRENCY_UNLOCK(); + return success; +} + +static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, + jint tech) { + int timeout = -1; + CONCURRENCY_LOCK(); + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + timeout = phLibNfc_GetMifareRawTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_ISO14443_4: + timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_FELICA: + timeout = phLibNfc_GetFelicaTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Felica timeout already in ms + } + break; + default: + ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); + break; + } + CONCURRENCY_UNLOCK(); + return timeout; +} + + +static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct nfc_jni_native_data *nat = NULL; + jclass cls; + jobject obj; + jfieldID f; + + TRACE("****** Init Native Structure ******"); + + /* Initialize native structure */ + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if(nat == NULL) + { + ALOGD("malloc of nfc_jni_native_data failed"); + return FALSE; + } + memset(nat, 0, sizeof(*nat)); + e->GetJavaVM(&(nat->vm)); + nat->env_version = e->GetVersion(); + nat->manager = e->NewGlobalRef(o); + + cls = e->GetObjectClass(o); + f = e->GetFieldID(cls, "mNative", "I"); + e->SetIntField(o, f, (jint)nat); + + /* Initialize native cached references */ + cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, + "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, + "notifyTargetDeselected","()V"); + + cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, + "notifySeFieldActivated", "()V"); + + cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, + "notifySeFieldDeactivated", "()V"); + + cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + TRACE("****** Init Native Structure OK ******"); + return TRUE; + +} + +/* Init/Deinit method */ +static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + int init_result = JNI_FALSE; +#ifdef TNFC_EMULATOR_ONLY + char value[PROPERTY_VALUE_MAX]; +#endif + jboolean result; + + CONCURRENCY_LOCK(); + +#ifdef TNFC_EMULATOR_ONLY + if (!property_get("ro.kernel.qemu", value, 0)) + { + ALOGE("NFC Initialization failed: not running in an emulator\n"); + goto clean_and_return; + } +#endif + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nat->seId = SMX_SECURE_ELEMENT_ID; + + nat->lto = 150; // LLCP_LTO + nat->miu = 128; // LLCP_MIU + // WKS indicates well-known services; 1 << sap for each supported SAP. + // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) + nat->wks = 0x13; // LLCP_WKS + nat->opt = 0; // LLCP_OPT + nat->p2p_initiator_modes = phNfc_eP2P_ALL; + nat->p2p_target_modes = 0x0E; // All passive except 106, active + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; + + nat->registry_info.MifareUL = TRUE; + nat->registry_info.MifareStd = TRUE; + nat->registry_info.ISO14443_4A = TRUE; + nat->registry_info.ISO14443_4B = TRUE; + nat->registry_info.Jewel = TRUE; + nat->registry_info.Felica = TRUE; + nat->registry_info.NFC = TRUE; + nat->registry_info.ISO15693 = TRUE; + + exported_nat = nat; + + /* Perform the initialization */ + init_result = nfc_jni_initialize(nat); + +clean_and_return: + CONCURRENCY_UNLOCK(); + + /* Convert the result and return */ + return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; +} + +static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) +{ + struct timespec ts; + NFCSTATUS status; + int result = JNI_FALSE; + struct nfc_jni_native_data *nat; + int bStackReset = FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Clear previous configuration */ + memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); + memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); + + /* Create the local semaphore */ + if (nfc_cb_data_init(&cb_data, NULL)) + { + TRACE("phLibNfc_Mgt_DeInitialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status == NFCSTATUS_PENDING) + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts) == -1) + { + ALOGW("Operation timed out"); + bStackReset = TRUE; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Failed to deinit the stack"); + bStackReset = TRUE; + } + } + else + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + bStackReset = TRUE; + } + nfc_cb_data_deinit(&cb_data); + } + else + { + ALOGE("Failed to create semaphore (errno=0x%08x)", errno); + bStackReset = TRUE; + } + + kill_client(nat); + + if(bStackReset == TRUE) + { + /* Complete deinit. failed, try hard restart of NFC */ + ALOGW("Reseting stack..."); + emergency_recovery(nat); + } + + result = nfc_jni_unconfigure_driver(nat); + + TRACE("NFC Deinitialized"); + + CONCURRENCY_UNLOCK(); + + return TRUE; +} + +/* Secure Element methods */ +static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { + NFCSTATUS ret; + jintArray list= NULL; + phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; + + TRACE("****** Get Secure Element List ******"); + + TRACE("phLibNfc_SE_GetSecureElementList()"); + REENTRANCE_LOCK(); + ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_SUCCESS) { + ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + return list; + } + TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + + TRACE("Nb SE: %d", se_count); + list =e->NewIntArray(se_count); + for (i = 0; i < se_count; i++) { + if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } + e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); + } + + e->DeleteLocalRef(list); + + return list; +} + +static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Select Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Virtual */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING) { + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Deselect Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Default */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, + nfc_jni_se_set_mode_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); + if (ret != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +/* Llcp methods */ + +static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + bool freeData = false; + jboolean result = JNI_FALSE; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data *cb_data; + + + CONCURRENCY_LOCK(); + + /* Memory allocation for cb_data + * This is on the heap because it is used by libnfc + * even after this call has succesfully finished. It is only freed + * upon link closure in nfc_jni_llcp_linkStatus_callback. + */ + cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(cb_data, (void*)nat)) + { + goto clean_and_return; + } + + /* Check LLCP compliancy */ + TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, + nfc_jni_checkLlcp_callback, + nfc_jni_llcp_linkStatus_callback, + (void*)cb_data); + REENTRANCE_UNLOCK(); + /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol + * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + freeData = true; + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data->sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data->status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(cb_data); + if (freeData) { + free(cb_data); + } + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Activate(hLlcpHandle); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_FALSE; + } +} + + + +static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, + jint nSap, jstring sn) +{ + NFCSTATUS ret; + jobject connectionlessSocket = NULL; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_native_data *nat; + phNfc_sData_t sWorkingBuffer = {NULL, 0}; + phNfc_sData_t serviceName = {NULL, 0}; + phLibNfc_Llcp_sLinkParameters_t sParams; + jclass clsNativeConnectionlessSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Allocate Working buffer length */ + phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); + sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, + NULL, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + + /* Create new NativeLlcpConnectionlessSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + { + goto error; + } + + /* Get NativeConnectionless class object */ + clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); + if(e->ExceptionCheck()) + { + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); + e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); + TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); + + /* Set the miu link of the connectionless socket */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); + e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); + TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); + e->SetIntField(connectionlessSocket, f,(jint)nSap); + TRACE("Connectionless socket SAP = %d\n",nSap); + + return connectionlessSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + + if (sWorkingBuffer.buffer != NULL) { + free(sWorkingBuffer.buffer); + } + + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + phNfc_sData_t serviceName; + struct nfc_jni_native_data *nat; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + ret = phLibNfc_Llcp_Close(hLlcpSocket); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Listen( hLlcpSocket, + nfc_jni_llcp_transport_listen_socket_callback, + (void*)hLlcpSocket); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + /* Close created socket */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpServiceSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + { + ALOGE("Llcp Socket object creation error"); + goto error; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); + if(e->ExceptionCheck()) + { + ALOGE("Llcp Socket get object class error"); + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); + TRACE("Service socket Handle = %02x\n",hLlcpSocket); + + /* Set socket linear buffer length */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField(serviceSocket, f,(jint)linearBufferLength); + TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField(serviceSocket, f,(jint)miu); + TRACE("Service socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField(serviceSocket, f,(jint)rw); + TRACE("Service socket RW = %d\n",rw); + + return serviceSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + struct nfc_jni_native_data *nat; + jclass clsNativeLlcpSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + return NULL; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGE("Llcp socket object creation error"); + return NULL; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGE("Get class object error"); + return NULL; + } + + /* Test if an SAP number is present */ + if(nSap != 0) + { + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + return NULL; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField(clientSocket, f,(jint)nSap); + TRACE("socket SAP = %d\n",nSap); + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hLlcpSocket); + TRACE("socket Handle = %02x\n",hLlcpSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + TRACE("socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + TRACE("socket RW = %d\n",rw); + + + return clientSocket; +} + +static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) +{ + TRACE("Last Error Status = 0x%02x",lastErrorStatus); + + if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) + { + return ERROR_BUFFER_TOO_SMALL; + } + else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) + { + return ERROR_INSUFFICIENT_RESOURCES; + } + else + { + return lastErrorStatus; + } +} + +static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) +{ + emergency_recovery(NULL); +} + +static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting init modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_initiator_modes = modes; +} + +static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting target modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_target_modes = modes; +} + +static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { + bool result = FALSE; + int load_result; + bool wasDisabled = FALSE; + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + NFCSTATUS status = NFCSTATUS_FAILED; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + result = FALSE; + goto clean_and_return; + } + + if (takeLock) + { + CONCURRENCY_LOCK(); + } + + /* Initialize Driver */ + if(!driverConfigured) + { + result = nfc_jni_configure_driver(nat); + wasDisabled = TRUE; + } + TRACE("com_android_nfc_NfcManager_doDownload()"); + + TRACE("Go in Download Mode"); + phLibNfc_Download_Mode(); + + TRACE("Load new Firmware Image"); + load_result = phLibNfc_Load_Firmware_Image(); + if(load_result != 0) + { + TRACE("Load new Firmware Image - status = %d",load_result); + result = FALSE; + goto clean_and_return; + } + + // Download + gInputParam.buffer = InputBuffer; + gInputParam.length = 0x01; + gOutputParam.buffer = OutputBuffer; + gOutputParam.length = 0x01; + + ALOGD("Download new Firmware"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + result = FALSE; + goto clean_and_return; + } + + /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we + try to download an old-style firmware on top of a new-style + firmware. Hence, this is expected behavior, and not an + error condition. */ + if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); + } + + /*Download is successful*/ + result = TRUE; +clean_and_return: + TRACE("phLibNfc_HW_Reset()"); + phLibNfc_HW_Reset(); + /* Deinitialize Driver */ + if(wasDisabled) + { + result = nfc_jni_unconfigure_driver(nat); + } + if (takeLock) + { + CONCURRENCY_UNLOCK(); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + return performDownload(nat, true); +} + +static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); + return e->NewStringUTF(buffer); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)com_android_nfc_NfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void *)com_android_nfc_NfcManager_init_native_struc}, + + {"doInitialize", "()Z", + (void *)com_android_nfc_NfcManager_initialize}, + + {"doDeinitialize", "()Z", + (void *)com_android_nfc_NfcManager_deinitialize}, + + {"enableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)com_android_nfc_NfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)com_android_nfc_NfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)com_android_nfc_NfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)com_android_nfc_NfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)com_android_nfc_NfcManager_doAbort}, + + {"doSetP2pInitiatorModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)com_android_nfc_NfcManager_doDump}, +}; + + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e) +{ + nfc_jni_native_monitor_t *nfc_jni_native_monitor; + + nfc_jni_native_monitor = nfc_jni_init_monitor(); + if(nfc_jni_native_monitor == NULL) + { + ALOGE("NFC Manager cannot recover native monitor %x\n", errno); + return -1; + } + + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; iRemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;iNewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/jni/com_android_nfc_list.cpp b/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/jni/com_android_nfc_list.h b/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk deleted file mode 100644 index 8ae792a..0000000 --- a/nxp/jni/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES:= \ - com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ - com_android_nfc_NativeLlcpServiceSocket.cpp \ - com_android_nfc_NativeLlcpSocket.cpp \ - com_android_nfc_NativeNfcManager.cpp \ - com_android_nfc_NativeNfcTag.cpp \ - com_android_nfc_NativeP2pDevice.cpp \ - com_android_nfc_NativeNfcSecureElement.cpp \ - com_android_nfc_list.cpp \ - com_android_nfc.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/libnfc-nxp/src \ - external/libnfc-nxp/inc - -LOCAL_SHARED_LIBRARIES := \ - libnativehelper \ - libcutils \ - libutils \ - libnfc \ - libhardware - -#LOCAL_CFLAGS += -O0 -g - -LOCAL_MODULE := libnfc_jni -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp deleted file mode 100644 index d794d6e..0000000 --- a/nxp/jni/com_android_nfc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "errno.h" -#include "com_android_nfc.h" -#include "com_android_nfc_list.h" -#include "phLibNfcStatus.h" - -/* - * JNI Initialization - */ -jint JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - JNIEnv *e; - - ALOGD("NFC Service : loading JNI\n"); - - // Check JNI version - if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) - return JNI_ERR; - - android::vm = jvm; - - if (android::register_com_android_nfc_NativeNfcManager(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcTag(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) - return JNI_ERR; - - return JNI_VERSION_1_6; -} - -namespace android { - -extern struct nfc_jni_native_data *exported_nat; - -JavaVM *vm; - -/* - * JNI Utils - */ -JNIEnv *nfc_get_env() -{ - JNIEnv *e; - if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Current thread is not attached to VM"); - phLibNfc_Mgt_Recovery(); - abort(); - } - return e; -} - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) -{ - /* Create semaphore */ - if(sem_init(&pCallbackData->sem, 0, 0) == -1) - { - ALOGE("Semaphore creation failed (errno=0x%08x)", errno); - return false; - } - - /* Set default status value */ - pCallbackData->status = NFCSTATUS_FAILED; - - /* Copy the context */ - pCallbackData->pContext = pContext; - - /* Add to active semaphore list */ - if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to add the semaphore to the list"); - } - - return true; -} - -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) -{ - /* Destroy semaphore */ - if (sem_destroy(&pCallbackData->sem)) - { - ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); - } - - /* Remove from active semaphore list */ - if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to remove semaphore from the list"); - } - -} - -void nfc_cb_data_releaseAll() -{ - nfc_jni_callback_data* pCallbackData; - - while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) - { - pCallbackData->status = NFCSTATUS_FAILED; - sem_post(&pCallbackData->sem); - } -} - -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj) -{ - jclass cls; - jobject obj; - jmethodID ctor; - - cls = e->FindClass(clsname); - if(cls == NULL) - { - return -1; - ALOGD("Find class error\n"); - } - - - ctor = e->GetMethodID(cls, "", "()V"); - - obj = e->NewObject(cls, ctor); - if(obj == NULL) - { - return -1; - ALOGD("Create object error\n"); - } - - *cached_obj = e->NewGlobalRef(obj); - if(*cached_obj == NULL) - { - e->DeleteLocalRef(obj); - ALOGD("Global ref error\n"); - return -1; - } - - e->DeleteLocalRef(obj); - - return 0; -} - - -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - /* Retrieve native structure address */ - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mNative", "I"); - return (struct nfc_jni_native_data*)e->GetIntField(o, f); -} - -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) -{ - return exported_nat; -} - -static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; - -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) -{ - - pthread_mutexattr_t recursive_attr; - - pthread_mutexattr_init(&recursive_attr); - pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); - - if(nfc_jni_native_monitor == NULL) - { - nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); - } - - if(nfc_jni_native_monitor != NULL) - { - memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); - - if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) - { - ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) - { - ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(!listInit(&nfc_jni_native_monitor->sem_list)) - { - ALOGE("NFC Manager Semaphore List creation failed"); - return NULL; - } - - LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); - - if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) - { - ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) - { - ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); - return NULL; - } - -} - - return nfc_jni_native_monitor; -} - -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) -{ - return nfc_jni_native_monitor; -} - - -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mMode", "S"); - - return e->GetShortField(o, f); -} - - -int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) -{ - - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedTechIndex", "I"); - - return e->GetIntField(o, f); - -} - -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - int connectedTech = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); - - if ((connectedTechIndex != -1) && (techTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(techTypes))) { - jint* technologies = e->GetIntArrayElements(techTypes, 0); - if (technologies != NULL) { - connectedTech = technologies[connectedTechIndex]; - e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); - } - } - - return connectedTech; - -} - -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jint connectedLibNfcType = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); - jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); - - if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { - jint* types = e->GetIntArrayElements(libNfcTypes, 0); - if (types != NULL) { - connectedLibNfcType = types[connectedTechIndex]; - e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); - } - } - return connectedLibNfcType; - -} - -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedHandle", "I"); - - return e->GetIntField(o, f); -} - -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jintArray techtypes; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechList","[I"); - - /* Read the techtypes */ - techtypes = (jintArray) e->GetObjectField(o, f); - - return techtypes; -} - - - -//Display status code -const char* nfc_jni_get_status_name(NFCSTATUS status) -{ - #define STATUS_ENTRY(status) { status, #status } - - struct status_entry { - NFCSTATUS code; - const char *name; - }; - - const struct status_entry sNameTable[] = { - STATUS_ENTRY(NFCSTATUS_SUCCESS), - STATUS_ENTRY(NFCSTATUS_FAILED), - STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), - STATUS_ENTRY(NFCSTATUS_TARGET_LOST), - STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), - STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), - STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_SHUTDOWN), - STATUS_ENTRY(NFCSTATUS_ABORTED), - STATUS_ENTRY(NFCSTATUS_REJECTED ), - STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), - STATUS_ENTRY(NFCSTATUS_PENDING), - STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), - STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), - STATUS_ENTRY(NFCSTATUS_BUSY), - STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), - STATUS_ENTRY(NFCSTATUS_DESELECTED), - STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), - STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), - STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), - STATUS_ENTRY(NFCSTATUS_RF_ERROR), - STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), - STATUS_ENTRY(NFCSTATUS_INVALID_STATE), - STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), - STATUS_ENTRY(NFCSTATUS_RELEASED), - STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), - STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), - STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_READ_FAILED), - STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), - STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), - STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), - STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), - STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), - STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), - }; - - int i = sizeof(sNameTable)/sizeof(status_entry); - - while(i>0) - { - i--; - if (sNameTable[i].code == PHNFCSTATUS(status)) - { - return sNameTable[i].name; - } - } - - return "UNKNOWN"; -} - -int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, - int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { - bool found = false; - for (int i = 0; i < listSize; i++) { - if (techList[i] == techToAdd) { - found = true; - break; - } - } - if (!found && listSize < maxListSize) { - techList[listSize] = techToAdd; - handleList[listSize] = handleToAdd; - typeList[listSize] = typeToAdd; - return listSize + 1; - } - else { - return listSize; - } -} - - -#define MAX_NUM_TECHNOLOGIES 32 - -/* - * Utility to get a technology tree and a corresponding handle list from a detected tag. - */ -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* libnfcTypeList) -{ - int technologies[MAX_NUM_TECHNOLOGIES]; - int handles[MAX_NUM_TECHNOLOGIES]; - int libnfctypes[MAX_NUM_TECHNOLOGIES]; - - int index = 0; - // TODO: This counts from up to down because on multi-protocols, the - // ISO handle is usually the second, and we prefer the ISO. Should implement - // a method to find the "preferred handle order" and use that instead, - // since we shouldn't have dependencies on the tech list ordering. - for (int target = count - 1; target >= 0; target--) { - int type = devList[target].psRemoteDevInfo->RemDevType; - int handle = devList[target].hTargetDev; - switch (type) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - break; - } - case phNfc_eISO14443_4B_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO14443_3A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - case phNfc_eISO14443_B_PICC: - { - // TODO a bug in libnfc will cause 14443-3B only cards - // to be returned as this type as well, but these cards - // are very rare. Hence assume it's -4B - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO15693_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); - }break; - case phNfc_eMifare_PICC: - { - // We don't want to be too clever here; libnfc has already determined - // it's a Mifare, so we only check for UL, for all other tags - // we assume it's a mifare classic. This should make us more - // future-proof. - int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; - switch(sak) - { - case 0x00: - // could be UL or UL-C - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); - break; - default: - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); - break; - } - }break; - case phNfc_eFelica_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); - }break; - case phNfc_eJewel_PICC: - { - // Jewel represented as NfcA - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - default: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); - } - } - } - - // Build the Java arrays - if (techList != NULL) { - *techList = e->NewIntArray(index); - e->SetIntArrayRegion(*techList, 0, index, technologies); - } - - if (handleList != NULL) { - *handleList = e->NewIntArray(index); - e->SetIntArrayRegion(*handleList, 0, index, handles); - } - - if (libnfcTypeList != NULL) { - *libnfcTypeList = e->NewIntArray(index); - e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); - } -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h deleted file mode 100644 index a44bcf0..0000000 --- a/nxp/jni/com_android_nfc.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_JNI_H__ -#define __COM_ANDROID_NFC_JNI_H__ - -#define LOG_TAG "NFCJNI" - -#include -#include - -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include - -} -#include // for property_get - - -/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ -#define DISCOVERY_MODE_TAG_READER 0 -#define DISCOVERY_MODE_NFCIP1 1 -#define DISCOVERY_MODE_CARD_EMULATION 2 - -#define DISCOVERY_MODE_TABLE_SIZE 3 - -#define DISCOVERY_MODE_DISABLED 0 -#define DISCOVERY_MODE_ENABLED 1 - -#define MODE_P2P_TARGET 0 -#define MODE_P2P_INITIATOR 1 - -/* Properties values */ -#define PROPERTY_LLCP_LTO 0 -#define PROPERTY_LLCP_MIU 1 -#define PROPERTY_LLCP_WKS 2 -#define PROPERTY_LLCP_OPT 3 -#define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 -#define PROPERTY_NFC_DISCOVERY_F 6 -#define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 - -/* Error codes */ -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -/* Pre-defined card read/write state values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_UNKNOWN_TYPE -1 -#define NDEF_TYPE1_TAG 1 -#define NDEF_TYPE2_TAG 2 -#define NDEF_TYPE3_TAG 3 -#define NDEF_TYPE4_TAG 4 -#define NDEF_MIFARE_CLASSIC_TAG 101 -#define NDEF_ICODE_SLI_TAG 102 - -/* Pre-defined tag type values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_MODE_READ_ONLY 1 -#define NDEF_MODE_READ_WRITE 2 -#define NDEF_MODE_UNKNOWN 3 - - -/* Name strings for target types. These *must* match the values in TagTechnology.java */ -#define TARGET_TYPE_UNKNOWN -1 -#define TARGET_TYPE_ISO14443_3A 1 -#define TARGET_TYPE_ISO14443_3B 2 -#define TARGET_TYPE_ISO14443_4 3 -#define TARGET_TYPE_FELICA 4 -#define TARGET_TYPE_ISO15693 5 -#define TARGET_TYPE_NDEF 6 -#define TARGET_TYPE_NDEF_FORMATABLE 7 -#define TARGET_TYPE_MIFARE_CLASSIC 8 -#define TARGET_TYPE_MIFARE_UL 9 - -#define SMX_SECURE_ELEMENT_ID 11259375 - -/* Maximum byte length of an AID. */ -#define AID_MAXLEN 16 - -/* Utility macros for logging */ -#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN - -#if 0 - #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); - #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#else - #define LOG_CALLBACK(...) - #define TRACE(...) -#endif - -struct nfc_jni_native_data -{ - /* Thread handle */ - pthread_t thread; - int running; - - /* Our VM */ - JavaVM *vm; - int env_version; - - /* Reference to the NFCManager instance */ - jobject manager; - - /* Cached objects */ - jobject cached_NfcTag; - jobject cached_P2pDevice; - - /* Target discovery configuration */ - int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - - /* Secure Element selected */ - int seId; - - /* LLCP params */ - int lto; - int miu; - int wks; - int opt; - - /* Tag detected */ - jobject tag; - - /* Lib Status */ - NFCSTATUS status; - - /* p2p modes */ - int p2p_initiator_modes; - int p2p_target_modes; - -}; - -typedef struct nfc_jni_native_monitor -{ - /* Mutex protecting native library against reentrance */ - pthread_mutex_t reentrance_mutex; - - /* Mutex protecting native library against concurrency */ - pthread_mutex_t concurrency_mutex; - - /* List used to track pending semaphores waiting for callback */ - struct listHead sem_list; - - /* List used to track incoming socket requests (and associated sync variables) */ - LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; - pthread_mutex_t incoming_socket_mutex; - pthread_cond_t incoming_socket_cond; - -} nfc_jni_native_monitor_t; - -typedef struct nfc_jni_callback_data -{ - /* Semaphore used to wait for callback */ - sem_t sem; - - /* Used to store the status sent by the callback */ - NFCSTATUS status; - - /* Used to provide a local context to the callback */ - void* pContext; - -} nfc_jni_callback_data_t; - -typedef struct nfc_jni_listen_data -{ - /* LLCP server socket receiving the connection request */ - phLibNfc_Handle pServerSocket; - - /* LLCP socket created from the connection request */ - phLibNfc_Handle pIncomingSocket; - - /* List entries */ - LIST_ENTRY(nfc_jni_listen_data) entries; - -} nfc_jni_listen_data_t; - -/* TODO: treat errors and add traces */ -#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) -#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) -#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) -#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) - -namespace android { - -extern JavaVM *vm; - -JNIEnv *nfc_get_env(); - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); -void nfc_cb_data_releaseAll(); - -const char* nfc_jni_get_status_name(NFCSTATUS status); -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj); -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); - -int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* typeList); - -/* P2P */ -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); - -/* TAG */ -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); - -/* LLCP */ -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e); -int register_com_android_nfc_NativeNfcTag(JNIEnv *e); -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); - -} // namespace android - -#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp deleted file mode 100644 index 188edb4..0000000 --- a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - pCallbackData->pContext = (void*)ssap; - TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_sendTo_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* -* Methods -*/ -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_SendTo()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SendTo(hRemoteDevice, - hLlcpSocket, - nsap, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) -{ - NFCSTATUS ret; - struct timespec ts; - uint8_t ssap; - jobject llcpPacket = NULL; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer; - jclass clsLlcpPacket; - jfieldID f; - jbyteArray receivedData = NULL; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create new LlcpPacket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) - { - ALOGE("Find LlcpPacket class error"); - goto clean_and_return; - } - - /* Get NativeConnectionless class object */ - clsLlcpPacket = e->GetObjectClass(llcpPacket); - if(e->ExceptionCheck()) - { - ALOGE("Get Object class error"); - goto clean_and_return; - } - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); - - sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); - sReceiveBuffer.length = linkMiu; - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - &cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ssap = (uint32_t)cb_data.pContext; - TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); - - /* Set Llcp Packet remote SAP */ - f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); - e->SetIntField(llcpPacket, f,(jbyte)ssap); - - /* Set Llcp Packet Buffer */ - ALOGD("Set LlcpPacket Data Buffer\n"); - f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); - receivedData = e->NewByteArray(sReceiveBuffer.length); - e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); - e->SetObjectField(llcpPacket, f, receivedData); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return llcpPacket; -} - -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - TRACE("Close Connectionless socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, - - {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, - - {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", - gMethods, NELEM(gMethods)); -} - -} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp deleted file mode 100644 index 92de3e4..0000000 --- a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode); -/* - * Callbacks - */ -static void nfc_jni_llcp_accept_socket_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -/* - * Utils - */ - -static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, - phLibNfc_Handle hServerSocket) -{ - nfc_jni_listen_data_t * pListenData; - phLibNfc_Handle pIncomingSocket = NULL; - - /* Look for a pending incoming connection on the current server */ - LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) - { - if (pListenData->pServerSocket == hServerSocket) - { - pIncomingSocket = pListenData->pIncomingSocket; - LIST_REMOVE(pListenData, entries); - free(pListenData); - break; - } - } - - return pIncomingSocket; -} - -/* - * Methods - */ -static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret = NFCSTATUS_SUCCESS; - struct timespec ts; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - jfieldID f; - jclass clsNativeLlcpSocket; - jobject clientSocket = NULL; - struct nfc_jni_callback_data cb_data; - phLibNfc_Handle hIncomingSocket, hServerSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Get server socket */ - hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Set socket options with the socket options of the service */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - - while(cb_data.status != NFCSTATUS_SUCCESS) - { - /* Wait for tag Notification */ - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { - pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); - } - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - /* Accept the incomming socket */ - TRACE("phLibNfc_Llcp_Accept()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Accept( hIncomingSocket, - &sOptions, - &sWorkingBuffer, - nfc_jni_llcp_transport_socket_err_callback, - nfc_jni_llcp_accept_socket_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - // NOTE: This may happen if link went down since incoming socket detected, then - // just drop it and start a new accept loop. - ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - continue; - } - TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ - ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); - } - } - - /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGD("LLCP Socket creation error"); - goto clean_and_return; - } - - /* Get NativeConnectionOriented class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGD("LLCP Socket get class object error"); - goto clean_and_return; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hIncomingSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - - TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return clientSocket; -} - -static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - TRACE("Close Service socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - /* TODO: implement accept abort */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("Close Service socket OK"); - return TRUE; - } - else - { - ALOGD("Close Service socket KO"); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_NativeLlcpServiceSocket_doAccept}, - - {"doClose", "()Z", - (void *)com_NativeLlcpServiceSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp deleted file mode 100644 index 0c0b830..0000000 --- a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_disconnect_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - TRACE("Socket connected\n"); - } - else - { - ALOGD("Socket not connected:"); - switch(nErrCode) - { - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: - { - ALOGD("> SAP NOT ACTIVE\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: - { - ALOGD("> SAP NOT FOUND\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: - { - ALOGD("> CONNECT REJECTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: - { - ALOGD("> CONNECT NOT ACCEPTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: - { - ALOGD("> SOCKET NOT AVAILABLE\n"); - }break; - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - - - -static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Methods - */ -static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_Llcp_Connect(%d)",nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Connect(hRemoteDevice, - hLlcpSocket, - nSap, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("LLCP Connect request failed"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) -{ - NFCSTATUS ret; - struct timespec ts; - phNfc_sData_t serviceName = {0}; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Service socket */ - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - - TRACE("phLibNfc_Llcp_ConnectByUri()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, - hLlcpSocket, - &serviceName, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_Send()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Send(hRemoteDevice, - hLlcpSocket, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jint result = -1; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); - sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); - - TRACE("phLibNfc_Llcp_Recv()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Recv(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_PENDING) - { - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - } - else if (ret == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - else - { - /* Return status should be either SUCCESS or PENDING */ - ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - -clean_and_return: - if (sReceiveBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.miu; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.rw; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnect}, - - {"doConnectBy", "(Ljava/lang/String;)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, - - {"doClose", "()Z", - (void *)com_android_nfc_NativeLlcpSocket_doClose}, - - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeLlcpSocket_doSend}, - - {"doReceive", "([B)I", - (void *)com_android_nfc_NativeLlcpSocket_doReceive}, - - {"doGetRemoteSocketMiu", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, - - {"doGetRemoteSocketRw", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, -}; - - -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp deleted file mode 100644 index 704ee6a..0000000 --- a/nxp/jni/com_android_nfc_NativeNfcManager.cpp +++ /dev/null @@ -1,2622 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "com_android_nfc.h" - -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -extern uint32_t libnfc_llc_error_count; - -static phLibNfc_sConfig_t gDrvCfg; -void *gHWRef; -static phNfc_sData_t gInputParam; -static phNfc_sData_t gOutputParam; - -uint8_t device_connected_flag; -static bool driverConfigured = FALSE; - -static phLibNfc_Handle hLlcpHandle; -static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; -static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; - -static jmethodID cached_NfcManager_notifyNdefMessageListeners; -static jmethodID cached_NfcManager_notifyTransactionListeners; -static jmethodID cached_NfcManager_notifyLlcpLinkActivation; -static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; -static jmethodID cached_NfcManager_notifyTargetDeselected; - -static jmethodID cached_NfcManager_notifySeFieldActivated; -static jmethodID cached_NfcManager_notifySeFieldDeactivated; - -static jmethodID cached_NfcManager_notifySeApduReceived; -static jmethodID cached_NfcManager_notifySeMifareAccess; -static jmethodID cached_NfcManager_notifySeEmvCardRemoval; - -namespace android { - -phLibNfc_Handle storedHandle = 0; - -struct nfc_jni_native_data *exported_nat = NULL; - -/* Internal functions declaration */ -static void *nfc_jni_client_thread(void *arg); -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_se_set_mode_callback(void *context, - phLibNfc_Handle handle, NFCSTATUS status); -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status); -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); -static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); - -/* - * Deferred callback called when client thread must be exited - */ -static void client_kill_deferred_call(void* arg) -{ - struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; - - nat->running = FALSE; -} - -static void kill_client(nfc_jni_native_data *nat) -{ - phDal4Nfc_Message_Wrapper_t wrapper; - phLibNfc_DeferredCall_t *pMsg; - - usleep(50000); - - ALOGD("Terminating client thread..."); - - pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); - pMsg->pCallback = client_kill_deferred_call; - pMsg->pParameter = (void*)nat; - - wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; - wrapper.msg.pMsgData = pMsg; - wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); - - phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); -} - -static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_ioctl_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_deinit_download_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) -{ - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - struct timespec ts; - NFCSTATUS status = NFCSTATUS_FAILED; - phLibNfc_StackCapabilities_t caps; - struct nfc_jni_callback_data cb_data; - bool result; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - if(update) - { - //deinit - TRACE("phLibNfc_Mgt_DeInitialize() (download)"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts)) - { - ALOGW("Deinitialization timed out (download)"); - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("Deinitialization FAILED (download)"); - } - TRACE("Deinitialization SUCCESS (download)"); - } - - result = performDownload(nat, false); - - if (!result) { - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - status = cb_data.status; - goto clean_and_return; - } - - /* ====== CAPABILITIES ======= */ - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /*Download is successful*/ - status = NFCSTATUS_SUCCESS; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return status; -} - -static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) -{ - char value[PROPERTY_VALUE_MAX]; - int result = FALSE; - NFCSTATUS status; - - /* ====== CONFIGURE DRIVER ======= */ - /* Configure hardware link */ - gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); - - TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); - REENTRANCE_UNLOCK(); - if(status == NFCSTATUS_ALREADY_INITIALISED) { - ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) - { - ALOGE("pthread_create failed"); - goto clean_and_return; - } - - driverConfigured = TRUE; - -clean_and_return: - return result; -} - -static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) -{ - int result = FALSE; - NFCSTATUS status; - - /* Unconfigure driver */ - TRACE("phLibNfc_Mgt_UnConfigureDriver()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); - } - else - { - ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = TRUE; - } - - driverConfigured = FALSE; - - return result; -} - -/* Initialization function */ -static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { - struct timespec ts; - uint8_t resp[16]; - NFCSTATUS status; - phLibNfc_StackCapabilities_t caps; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; - phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; - struct nfc_jni_callback_data cb_data; - uint8_t firmware_status; - uint8_t update = TRUE; - int result = JNI_FALSE; - const hw_module_t* hw_module; - nfc_pn544_device_t* pn544_dev = NULL; - int ret = 0; - ALOGD("Start Initialization\n"); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Get EEPROM values and device port from product-specific settings */ - ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); - if (ret) { - ALOGE("hw_get_module() failed."); - goto clean_and_return; - } - ret = nfc_pn544_open(hw_module, &pn544_dev); - if (ret) { - ALOGE("Could not open pn544 hw_module."); - goto clean_and_return; - } - if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { - ALOGE("Could not load EEPROM settings"); - goto clean_and_return; - } - - /* Reset device connected handle */ - device_connected_flag = 0; - - /* Reset stored handle */ - storedHandle = 0; - - /* Initialize Driver */ - if(!driverConfigured) - { - nfc_jni_configure_driver(nat); - } - - /* ====== INITIALIZE ======= */ - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - update = FALSE; - goto force_download; - } - TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - update = FALSE; - goto force_download; - } - - /* ====== CAPABILITIES ======= */ - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /* ====== FIRMWARE VERSION ======= */ - if(caps.psDevCapabilities.firmware_update_info) - { -force_download: - for (i=0; i<3; i++) - { - TRACE("Firmware version not UpToDate"); - status = nfc_jni_download_locked(nat, update); - if(status == NFCSTATUS_SUCCESS) - { - ALOGI("Firmware update SUCCESS"); - break; - } - ALOGW("Firmware update FAILED"); - update = FALSE; - } - if(i>=3) - { - ALOGE("Unable to update firmware, giving up"); - goto clean_and_return; - } - } - else - { - TRACE("Firmware version UpToDate"); - } - /* ====== EEPROM SETTINGS ======= */ - - // Update EEPROM settings - TRACE("****** START EEPROM SETTINGS UPDATE ******"); - for (i = 0; i < pn544_dev->num_eeprom_settings; i++) - { - char eeprom_property[PROPERTY_KEY_MAX]; - char eeprom_value[PROPERTY_VALUE_MAX]; - uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); - TRACE("> EEPROM SETTING: %d", i); - - // Check for override of this EEPROM value in properties - snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", - eeprom_base[1], eeprom_base[2]); - TRACE(">> Checking property: %s", eeprom_property); - if (property_get(eeprom_property, eeprom_value, "") == 2) { - int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); - ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", - eeprom_base[1], eeprom_base[2], eeprom_value_num); - eeprom_base[3] = eeprom_value_num; - } - - TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], - eeprom_base[3]); - gInputParam.buffer = eeprom_base; - gInputParam.length = 0x04; - gOutputParam.buffer = resp; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if (cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - } - TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); - - /* ====== SECURE ELEMENTS ======= */ - - REENTRANCE_LOCK(); - ALOGD("phLibNfc_SE_GetSecureElementList()"); - status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - - ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i < No_SE; i++) - { - if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); - } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); - } - - /* Set SE mode - Off */ - REENTRANCE_LOCK(); - status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, - phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - } - - /* ====== LLCP ======= */ - - /* LLCP Params */ - TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); - LlcpConfigInfo.miu = nat->miu; - LlcpConfigInfo.lto = nat->lto; - LlcpConfigInfo.wks = nat->wks; - LlcpConfigInfo.option = nat->opt; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, - nfc_jni_llcpcfg_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* ===== DISCOVERY ==== */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.Duration = 300000; /* in ms */ - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Register for the card emulation mode */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); - - - /* ====== END ======= */ - - ALOGI("NFC Initialized"); - - result = TRUE; - -clean_and_return: - if (result != TRUE) - { - if(nat) - { - kill_client(nat); - } - } - if (pn544_dev != NULL) { - nfc_pn544_close(pn544_dev); - } - nfc_cb_data_deinit(&cb_data); - - return result; -} - -static int is_user_build() { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.type", value, ""); - return !strncmp("user", value, PROPERTY_VALUE_MAX); -} - -/* - * Last-chance fallback when there is no clean way to recover - * Performs a software reset - */ -void emergency_recovery(struct nfc_jni_native_data *nat) { - if (!is_user_build()) { - ALOGE("emergency_recovery: force restart of NFC service"); - } else { - // dont recover immediately, so we can debug - unsigned int t; - for (t=1; t < 1000000; t <<= 1) { - ALOGE("emergency_recovery: NFC stack dead-locked"); - sleep(t); - } - } - phLibNfc_Mgt_Recovery(); - abort(); // force a noisy crash -} - -void nfc_jni_reset_timeout_values() -{ - REENTRANCE_LOCK(); - phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); - phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); - phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); - phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); - REENTRANCE_UNLOCK(); -} - -/* - * Restart the polling loop when unable to perform disconnect - */ -void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) -{ - nfc_jni_start_discovery_locked(nat, true); -} - - /* - * Utility to recover UID from target infos - */ -static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - phNfc_sData_t uid; - - switch(psRemoteDevInfo->RemDevType) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_3A_PICC: - case phNfc_eMifare_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; - break; - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; - uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); - break; - case phNfc_eFelica_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; - uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; - break; - case phNfc_eJewel_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; - break; - case phNfc_eISO15693_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; - break; - case phNfc_eNfcIP1_Target: - case phNfc_eNfcIP1_Initiator: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; - uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; - break; - default: - uid.buffer = NULL; - uid.length = 0; - break; - } - - return uid; -} - -/* - * NFC stack message processing - */ -static void *nfc_jni_client_thread(void *arg) -{ - struct nfc_jni_native_data *nat; - JNIEnv *e; - JavaVMAttachArgs thread_args; - phDal4Nfc_Message_Wrapper_t wrapper; - - nat = (struct nfc_jni_native_data *)arg; - - thread_args.name = "NFC Message Loop"; - thread_args.version = nat->env_version; - thread_args.group = NULL; - - nat->vm->AttachCurrentThread(&e, &thread_args); - pthread_setname_np(pthread_self(), "message"); - - TRACE("NFC client started"); - nat->running = TRUE; - while(nat->running == TRUE) - { - /* Fetch next message from the NFC stack message queue */ - if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, - sizeof(phLibNfc_Message_t), 0, 0) == -1) - { - ALOGE("NFC client received bad message"); - continue; - } - - switch(wrapper.msg.eMsgType) - { - case PH_LIBNFC_DEFERREDCALL_MSG: - { - phLibNfc_DeferredCall_t *msg = - (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); - - REENTRANCE_LOCK(); - msg->pCallback(msg->pParameter); - REENTRANCE_UNLOCK(); - - break; - } - } - } - TRACE("NFC client stopped"); - - nat->vm->DetachCurrentThread(); - - return NULL; -} - -extern uint8_t nfc_jni_is_ndef; -extern uint8_t *nfc_jni_ndef_buf; -extern uint32_t nfc_jni_ndef_buf_len; - -static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = -{ - 3, - { 0x46, 0x66, 0x6D } -}; - -/* - * Callbacks - */ - -/* P2P - LLCP callbacks */ -static void nfc_jni_llcp_linkStatus_callback(void *pContext, - phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) -{ - phFriNfc_Llcp_sLinkParameters_t sLinkParams; - JNIEnv *e; - NFCSTATUS status; - - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; - - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - /* Update link status */ - g_eLinkStatus = eLinkStatus; - - if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) - { - REENTRANCE_LOCK(); - status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGW("GetRemote Info failded - Status = %02x",status); - } - else - { - ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, - sLinkParams.miu, - sLinkParams.option, - sLinkParams.wks); - device_connected_flag = 1; - } - } - else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) - { - ALOGI("LLCP Link deactivated"); - free(pContextData); - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Reset incoming socket list */ - while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) - { - pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); - LIST_REMOVE(pListenData, entries); - free(pListenData); - } - - /* Notify manager that the LLCP is lost or deactivated */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } -} - -static void nfc_jni_checkLlcp_callback(void *context, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; - - LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, - phLibNfc_Handle hIncomingSocket) -{ - phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - - /* Store the connection request */ - pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); - if (pListenData == NULL) - { - ALOGE("Failed to create structure to handle incoming LLCP connection request"); - goto clean_and_return; - } - pListenData->pServerSocket = hServiceSocket; - pListenData->pIncomingSocket = hIncomingSocket; - LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); - - /* Signal pending accept operations that the list is updated */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - -clean_and_return: - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); -} - -void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode) -{ - PHNFC_UNUSED_VARIABLE(pContext); - - TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); - - if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) - { - ALOGW("Frame Rejected - Disconnected"); - } - else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) - { - ALOGD("Socket Disconnected"); - } -} - - -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_discover_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNoOfRemoteDev) -{ - // Always prefer p2p targets over other targets. Otherwise, select the first target - // reported. - uint8_t preferred_index = 0; - for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { - if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { - preferred_index = i; - } - } - return preferred_index; -} - -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status) -{ - JNIEnv *e; - NFCSTATUS ret; - jclass tag_cls = NULL; - jobject target_array; - jobject tag; - jmethodID ctor; - jfieldID f; - const char * typeName; - jbyteArray tagUid; - jbyteArray generalBytes = NULL; - struct nfc_jni_native_data *nat; - struct timespec ts; - phNfc_sData_t data; - int i; - int target_index = 0; // Target that will be reported (if multiple can be >0) - - nat = (struct nfc_jni_native_data *)pContext; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); - - /* Notify manager that a target was deselected */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); - TRACE("Discovered %d tags", uNofRemoteDev); - - target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); - - /* Reset device connected flag */ - device_connected_flag = 1; - phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; - phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - - tag_cls = e->GetObjectClass(nat->cached_P2pDevice); - if(e->ExceptionCheck()) - { - ALOGE("Get Object Class Error"); - kill_client(nat); - return; - } - - /* New target instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - /* Set P2P Target mode */ - f = e->GetFieldID(tag_cls, "mMode", "I"); - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - ALOGD("Discovered P2P Initiator"); - e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); - } - else - { - ALOGD("Discovered P2P Target"); - e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); - } - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - /* Set General Bytes */ - f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes length ="); - for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) - { - ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); - } - - generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - - e->SetByteArrayRegion(generalBytes, 0, - remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, - (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); - - e->SetObjectField(tag, f, generalBytes); - } - - /* Set tag handle */ - f = e->GetFieldID(tag_cls, "mHandle", "I"); - e->SetIntField(tag, f,(jint)remDevHandle); - TRACE("Target handle = 0x%08x",remDevHandle); - } - else - { - tag_cls = e->GetObjectClass(nat->cached_NfcTag); - if(e->ExceptionCheck()) - { - kill_client(nat); - return; - } - - /* New tag instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - bool multi_protocol = false; - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - TRACE("Multiple Protocol TAG detected\n"); - multi_protocol = true; - } - - /* Set tag UID */ - f = e->GetFieldID(tag_cls, "mUid", "[B"); - data = get_target_uid(remDevInfo); - tagUid = e->NewByteArray(data.length); - if(data.length > 0) - { - e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); - } - e->SetObjectField(tag, f, tagUid); - - /* Generate technology list */ - jintArray techList; - jintArray handleList; - jintArray typeList; - nfc_jni_get_technology_tree(e, psRemoteDevList, - multi_protocol ? uNofRemoteDev : 1, - &techList, &handleList, &typeList); - - /* Push the technology list into the java object */ - f = e->GetFieldID(tag_cls, "mTechList", "[I"); - e->SetObjectField(tag, f, techList); - - f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); - e->SetObjectField(tag, f, handleList); - - f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); - e->SetObjectField(tag, f, typeList); - - f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); - e->SetIntField(tag, f,(jint)-1); - - f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); - e->SetIntField(tag, f,(jint)-1); - } - - storedHandle = remDevHandle; - if (nat->tag != NULL) { - e->DeleteGlobalRef(nat->tag); - } - nat->tag = e->NewGlobalRef(tag); - - /* Notify the service */ - TRACE("Notify Nfc Service"); - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - /* Store the hanlde of the P2P device */ - hLlcpHandle = remDevHandle; - - /* Notify manager that new a P2P device was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - /* Notify manager that new a tag was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - e->DeleteLocalRef(tag); - } -} - -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_init_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_deinit_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Card Emulation callback */ -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) -{ - JNIEnv *e; - jobject tmp_array = NULL; - jobject mifare_block = NULL; - struct nfc_jni_native_data *nat; - phNfc_sData_t *aid; - phNfc_sData_t *mifare_command; - struct nfc_jni_callback_data *pCallbackData; - int i=0; - - LOG_CALLBACK("nfc_jni_transaction_callback", status); - - nat = (struct nfc_jni_native_data *)context; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_SUCCESS) - { - switch(evt_type) - { - case phLibNfc_eSE_EvtStartTransaction: - { - TRACE("> SE EVT_START_TRANSACTION"); - if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) - { - aid = &(evt_info->UiccEvtInfo.aid); - - ALOGD("> AID DETECTED"); - - if(aid != NULL) - { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); - } - ALOGD("> AID: %s", aid_str); - - tmp_array = e->NewByteArray(aid->length); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - goto error; - } - - TRACE("Notify Nfc Service"); - /* Notify manager that a new event occurred on a SE */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - ALOGD("> NO AID DETECTED"); - } - }break; - - case phLibNfc_eSE_EvtApduReceived: - { - phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); - TRACE("> SE EVT_APDU_RECEIVED"); - - if (apdu != NULL) { - TRACE(" APDU length=%d", apdu->length); - tmp_array = e->NewByteArray(apdu->length); - if (tmp_array == NULL) { - goto error; - } - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); - if (e->ExceptionCheck()) { - goto error; - } - } else { - TRACE(" APDU EMPTY"); - } - - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); - }break; - - case phLibNfc_eSE_EvtCardRemoval: - { - TRACE("> SE EVT_EMV_CARD_REMOVAL"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); - }break; - - case phLibNfc_eSE_EvtMifareAccess: - { - TRACE("> SE EVT_MIFARE_ACCESS"); - mifare_command = &(evt_info->UiccEvtInfo.aid); - TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); - tmp_array = e->NewByteArray(2); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); - }break; - - case phLibNfc_eSE_EvtFieldOn: - { - TRACE("> SE EVT_FIELD_ON"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); - }break; - - case phLibNfc_eSE_EvtFieldOff: - { - TRACE("> SE EVT_FIELD_OFF"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); - }break; - - default: - { - TRACE("Unknown SE event"); - }break; - } - } - else - { - ALOGE("SE transaction notification error"); - goto error; - } - - /* Function finished, now clean and return */ - goto clean_and_return; - - error: - /* In case of error, just discard the notification */ - ALOGE("Failed to send SE transaction notification"); - e->ExceptionClear(); - - clean_and_return: - if(tmp_array != NULL) - { - e->DeleteLocalRef(tmp_array); - } -} - -static void nfc_jni_se_set_mode_callback(void *pContext, - phLibNfc_Handle handle, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* - * NFCManager methods - */ - -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) -{ - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ - nfc_jni_reset_timeout_values(); - - /* Reload the p2p modes */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Start Polling loop */ - TRACE("****** Start NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, - nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - -static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) -{ - phLibNfc_sADD_Cfg_t discovery_cfg; - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - discovery_cfg.PollDevInfo.PollEnabled = 0; - discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; - discovery_cfg.NfcIP_Target_Mode = 0; - discovery_cfg.NfcIP_Tgt_Disable = TRUE; - - /* Start Polling loop */ - TRACE("****** Stop NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - - -static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nfc_jni_stop_discovery_locked(nat); - - CONCURRENCY_UNLOCK(); - -} - -static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - nat = nfc_jni_get_nat(e, o); - - /* Register callback for remote device notifications. - * Must re-register every time we turn on discovery, since other operations - * (such as opening the Secure Element) can change the remote device - * notification callback*/ - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", - nat->registry_info.Jewel==TRUE?"J":"", - nat->registry_info.MifareUL==TRUE?"UL":"", - nat->registry_info.MifareStd==TRUE?"Mi":"", - nat->registry_info.Felica==TRUE?"F":"", - nat->registry_info.ISO14443_4A==TRUE?"4A":"", - nat->registry_info.ISO14443_4B==TRUE?"4B":"", - nat->registry_info.NFC==TRUE?"P2P":"", - nat->registry_info.ISO15693==TRUE?"R":"", ret); - - nfc_jni_start_discovery_locked(nat, false); -clean_and_return: - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { - CONCURRENCY_LOCK(); - nfc_jni_reset_timeout_values(); - CONCURRENCY_UNLOCK(); -} - -static void setFelicaTimeout(jint timeout) { - // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. - // It can be set to 0 to disable the timeout altogether, in which case we - // use the sw watchdog as a fallback. - if (timeout <= 255) { - phLibNfc_SetFelicaTimeout(timeout); - } else { - // Disable hw timeout, use sw watchdog for timeout - phLibNfc_SetFelicaTimeout(0); - phLibNfc_SetHciTimeout(timeout); - } - -} -// Calculates ceiling log2 of value -static unsigned int log2(int value) { - unsigned int ret = 0; - bool isPowerOf2 = ((value & (value - 1)) == 0); - while ( (value >> ret) > 1 ) ret++; - if (!isPowerOf2) ret++; - return ret; -} - -// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X -// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X -// -// We keep the constant part of the formula in a static; note the factor -// 1000 off, which is due to the fact that the formula calculates seconds, -// but this method gets milliseconds as an argument. -static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; - -static int calcTimeout(int timeout_in_ms) { - // timeout = (256 * 16 / 13560000) * 2 ^ X - // First find the first X for which timeout > requested timeout - return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); -} - -static void setIsoDepTimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - // Then re-compute the actual timeout based on X - double actual_timeout = nxp_nfc_timeout_factor * (1 << value); - // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, - // but it will take some time to get back through the sw layers. - // 500 ms should be enough). - phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); - value |= 0x10; // bit 4 to enable timeout - phLibNfc_SetIsoXchgTimeout(value); - } - else { - // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout - // must be disabled completely, to prevent the PN544 from aborting - // the transaction. We reuse the HCI sw watchdog to catch the timeout - // in that case. - phLibNfc_SetIsoXchgTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static void setNfcATimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - phLibNfc_SetMifareRawTimeout(value); - } - else { - // Disable mifare raw timeout, use HCI sw watchdog instead - phLibNfc_SetMifareRawTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, - jint tech, jint timeout) { - bool success = false; - CONCURRENCY_LOCK(); - if (timeout <= 0) { - ALOGE("Timeout must be positive."); - return false; - } else { - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - setNfcATimeout(timeout); - success = true; - break; - case TARGET_TYPE_ISO14443_4: - setIsoDepTimeout(timeout); - success = true; - break; - case TARGET_TYPE_FELICA: - setFelicaTimeout(timeout); - success = true; - break; - default: - ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); - success = false; - } - } - CONCURRENCY_UNLOCK(); - return success; -} - -static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, - jint tech) { - int timeout = -1; - CONCURRENCY_LOCK(); - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - timeout = phLibNfc_GetMifareRawTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_ISO14443_4: - timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_FELICA: - timeout = phLibNfc_GetFelicaTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Felica timeout already in ms - } - break; - default: - ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); - break; - } - CONCURRENCY_UNLOCK(); - return timeout; -} - - -static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct nfc_jni_native_data *nat = NULL; - jclass cls; - jobject obj; - jfieldID f; - - TRACE("****** Init Native Structure ******"); - - /* Initialize native structure */ - nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); - if(nat == NULL) - { - ALOGD("malloc of nfc_jni_native_data failed"); - return FALSE; - } - memset(nat, 0, sizeof(*nat)); - e->GetJavaVM(&(nat->vm)); - nat->env_version = e->GetVersion(); - nat->manager = e->NewGlobalRef(o); - - cls = e->GetObjectClass(o); - f = e->GetFieldID(cls, "mNative", "I"); - e->SetIntField(o, f, (jint)nat); - - /* Initialize native cached references */ - cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); - - cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, - "notifyTransactionListeners", "([B)V"); - - cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, - "notifyTargetDeselected","()V"); - - cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, - "notifySeFieldActivated", "()V"); - - cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, - "notifySeFieldDeactivated", "()V"); - - cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, - "notifySeApduReceived", "([B)V"); - - cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, - "notifySeMifareAccess", "([B)V"); - - cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, - "notifySeEmvCardRemoval", "()V"); - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - TRACE("****** Init Native Structure OK ******"); - return TRUE; - -} - -/* Init/Deinit method */ -static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - int init_result = JNI_FALSE; -#ifdef TNFC_EMULATOR_ONLY - char value[PROPERTY_VALUE_MAX]; -#endif - jboolean result; - - CONCURRENCY_LOCK(); - -#ifdef TNFC_EMULATOR_ONLY - if (!property_get("ro.kernel.qemu", value, 0)) - { - ALOGE("NFC Initialization failed: not running in an emulator\n"); - goto clean_and_return; - } -#endif - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nat->seId = SMX_SECURE_ELEMENT_ID; - - nat->lto = 150; // LLCP_LTO - nat->miu = 128; // LLCP_MIU - // WKS indicates well-known services; 1 << sap for each supported SAP. - // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) - nat->wks = 0x13; // LLCP_WKS - nat->opt = 0; // LLCP_OPT - nat->p2p_initiator_modes = phNfc_eP2P_ALL; - nat->p2p_target_modes = 0x0E; // All passive except 106, active - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; - - nat->registry_info.MifareUL = TRUE; - nat->registry_info.MifareStd = TRUE; - nat->registry_info.ISO14443_4A = TRUE; - nat->registry_info.ISO14443_4B = TRUE; - nat->registry_info.Jewel = TRUE; - nat->registry_info.Felica = TRUE; - nat->registry_info.NFC = TRUE; - nat->registry_info.ISO15693 = TRUE; - - exported_nat = nat; - - /* Perform the initialization */ - init_result = nfc_jni_initialize(nat); - -clean_and_return: - CONCURRENCY_UNLOCK(); - - /* Convert the result and return */ - return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; -} - -static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) -{ - struct timespec ts; - NFCSTATUS status; - int result = JNI_FALSE; - struct nfc_jni_native_data *nat; - int bStackReset = FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Clear previous configuration */ - memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); - memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); - - /* Create the local semaphore */ - if (nfc_cb_data_init(&cb_data, NULL)) - { - TRACE("phLibNfc_Mgt_DeInitialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status == NFCSTATUS_PENDING) - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts) == -1) - { - ALOGW("Operation timed out"); - bStackReset = TRUE; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Failed to deinit the stack"); - bStackReset = TRUE; - } - } - else - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - bStackReset = TRUE; - } - nfc_cb_data_deinit(&cb_data); - } - else - { - ALOGE("Failed to create semaphore (errno=0x%08x)", errno); - bStackReset = TRUE; - } - - kill_client(nat); - - if(bStackReset == TRUE) - { - /* Complete deinit. failed, try hard restart of NFC */ - ALOGW("Reseting stack..."); - emergency_recovery(nat); - } - - result = nfc_jni_unconfigure_driver(nat); - - TRACE("NFC Deinitialized"); - - CONCURRENCY_UNLOCK(); - - return TRUE; -} - -/* Secure Element methods */ -static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { - NFCSTATUS ret; - jintArray list= NULL; - phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; - - TRACE("****** Get Secure Element List ******"); - - TRACE("phLibNfc_SE_GetSecureElementList()"); - REENTRANCE_LOCK(); - ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_SUCCESS) { - ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - return list; - } - TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - - TRACE("Nb SE: %d", se_count); - list =e->NewIntArray(se_count); - for (i = 0; i < se_count; i++) { - if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } - e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); - } - - e->DeleteLocalRef(list); - - return list; -} - -static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Select Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Virtual */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING) { - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Deselect Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Default */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, - nfc_jni_se_set_mode_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); - if (ret != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -/* Llcp methods */ - -static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - bool freeData = false; - jboolean result = JNI_FALSE; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data *cb_data; - - - CONCURRENCY_LOCK(); - - /* Memory allocation for cb_data - * This is on the heap because it is used by libnfc - * even after this call has succesfully finished. It is only freed - * upon link closure in nfc_jni_llcp_linkStatus_callback. - */ - cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(cb_data, (void*)nat)) - { - goto clean_and_return; - } - - /* Check LLCP compliancy */ - TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, - nfc_jni_checkLlcp_callback, - nfc_jni_llcp_linkStatus_callback, - (void*)cb_data); - REENTRANCE_UNLOCK(); - /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol - * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - freeData = true; - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data->sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data->status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(cb_data); - if (freeData) { - free(cb_data); - } - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Activate(hLlcpHandle); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_FALSE; - } -} - - - -static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, - jint nSap, jstring sn) -{ - NFCSTATUS ret; - jobject connectionlessSocket = NULL; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_native_data *nat; - phNfc_sData_t sWorkingBuffer = {NULL, 0}; - phNfc_sData_t serviceName = {NULL, 0}; - phLibNfc_Llcp_sLinkParameters_t sParams; - jclass clsNativeConnectionlessSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Allocate Working buffer length */ - phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); - sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, - NULL, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - - /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) - { - goto error; - } - - /* Get NativeConnectionless class object */ - clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); - if(e->ExceptionCheck()) - { - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); - e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); - TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); - - /* Set the miu link of the connectionless socket */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); - e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); - TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); - e->SetIntField(connectionlessSocket, f,(jint)nSap); - TRACE("Connectionless socket SAP = %d\n",nSap); - - return connectionlessSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - - if (sWorkingBuffer.buffer != NULL) { - free(sWorkingBuffer.buffer); - } - - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - phNfc_sData_t serviceName; - struct nfc_jni_native_data *nat; - jobject serviceSocket = NULL; - jclass clsNativeLlcpServiceSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - ret = phLibNfc_Llcp_Close(hLlcpSocket); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Listen( hLlcpSocket, - nfc_jni_llcp_transport_listen_socket_callback, - (void*)hLlcpSocket); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - /* Close created socket */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) - { - ALOGE("Llcp Socket object creation error"); - goto error; - } - - /* Get NativeLlcpServiceSocket class object */ - clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); - if(e->ExceptionCheck()) - { - ALOGE("Llcp Socket get object class error"); - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); - e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); - TRACE("Service socket Handle = %02x\n",hLlcpSocket); - - /* Set socket linear buffer length */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); - e->SetIntField(serviceSocket, f,(jint)linearBufferLength); - TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); - e->SetIntField(serviceSocket, f,(jint)miu); - TRACE("Service socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); - e->SetIntField(serviceSocket, f,(jint)rw); - TRACE("Service socket RW = %d\n",rw); - - return serviceSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) -{ - jobject clientSocket = NULL; - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - struct nfc_jni_native_data *nat; - jclass clsNativeLlcpSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - return NULL; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGE("Llcp socket object creation error"); - return NULL; - } - - /* Get NativeConnectionless class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGE("Get class object error"); - return NULL; - } - - /* Test if an SAP number is present */ - if(nSap != 0) - { - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - return NULL; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); - e->SetIntField(clientSocket, f,(jint)nSap); - TRACE("socket SAP = %d\n",nSap); - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hLlcpSocket); - TRACE("socket Handle = %02x\n",hLlcpSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - TRACE("socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - TRACE("socket RW = %d\n",rw); - - - return clientSocket; -} - -static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) -{ - TRACE("Last Error Status = 0x%02x",lastErrorStatus); - - if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) - { - return ERROR_BUFFER_TOO_SMALL; - } - else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) - { - return ERROR_INSUFFICIENT_RESOURCES; - } - else - { - return lastErrorStatus; - } -} - -static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) -{ - emergency_recovery(NULL); -} - -static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting init modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_initiator_modes = modes; -} - -static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting target modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_target_modes = modes; -} - -static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { - bool result = FALSE; - int load_result; - bool wasDisabled = FALSE; - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - NFCSTATUS status = NFCSTATUS_FAILED; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - result = FALSE; - goto clean_and_return; - } - - if (takeLock) - { - CONCURRENCY_LOCK(); - } - - /* Initialize Driver */ - if(!driverConfigured) - { - result = nfc_jni_configure_driver(nat); - wasDisabled = TRUE; - } - TRACE("com_android_nfc_NfcManager_doDownload()"); - - TRACE("Go in Download Mode"); - phLibNfc_Download_Mode(); - - TRACE("Load new Firmware Image"); - load_result = phLibNfc_Load_Firmware_Image(); - if(load_result != 0) - { - TRACE("Load new Firmware Image - status = %d",load_result); - result = FALSE; - goto clean_and_return; - } - - // Download - gInputParam.buffer = InputBuffer; - gInputParam.length = 0x01; - gOutputParam.buffer = OutputBuffer; - gOutputParam.length = 0x01; - - ALOGD("Download new Firmware"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - result = FALSE; - goto clean_and_return; - } - - /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we - try to download an old-style firmware on top of a new-style - firmware. Hence, this is expected behavior, and not an - error condition. */ - if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); - } - - /*Download is successful*/ - result = TRUE; -clean_and_return: - TRACE("phLibNfc_HW_Reset()"); - phLibNfc_HW_Reset(); - /* Deinitialize Driver */ - if(wasDisabled) - { - result = nfc_jni_unconfigure_driver(nat); - } - if (takeLock) - { - CONCURRENCY_UNLOCK(); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - return performDownload(nat, true); -} - -static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); - return e->NewStringUTF(buffer); -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doDownload", "()Z", - (void *)com_android_nfc_NfcManager_doDownload}, - - {"initializeNativeStructure", "()Z", - (void *)com_android_nfc_NfcManager_init_native_struc}, - - {"doInitialize", "()Z", - (void *)com_android_nfc_NfcManager_initialize}, - - {"doDeinitialize", "()Z", - (void *)com_android_nfc_NfcManager_deinitialize}, - - {"enableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_enableDiscovery}, - - {"doGetSecureElementList", "()[I", - (void *)com_android_nfc_NfcManager_doGetSecureElementList}, - - {"doSelectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doSelectSecureElement}, - - {"doDeselectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, - - {"doCheckLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doCheckLlcp}, - - {"doActivateLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doActivateLlcp}, - - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, - - {"doGetLastError", "()I", - (void *)com_android_nfc_NfcManager_doGetLastError}, - - {"disableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_disableDiscovery}, - - {"doSetTimeout", "(II)Z", - (void *)com_android_nfc_NfcManager_doSetTimeout}, - - {"doGetTimeout", "(I)I", - (void *)com_android_nfc_NfcManager_doGetTimeout}, - - {"doResetTimeouts", "()V", - (void *)com_android_nfc_NfcManager_doResetTimeouts}, - - {"doAbort", "()V", - (void *)com_android_nfc_NfcManager_doAbort}, - - {"doSetP2pInitiatorModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, - - {"doSetP2pTargetModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, - - {"doDump", "()Ljava/lang/String;", - (void *)com_android_nfc_NfcManager_doDump}, -}; - - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e) -{ - nfc_jni_native_monitor_t *nfc_jni_native_monitor; - - nfc_jni_native_monitor = nfc_jni_init_monitor(); - if(nfc_jni_native_monitor == NULL) - { - ALOGE("NFC Manager cannot recover native monitor %x\n", errno); - return -1; - } - - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", - gMethods, NELEM(gMethods)); -} - -} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp deleted file mode 100755 index bf0bffc..0000000 --- a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "com_android_nfc.h" - -static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; -static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; -static phNfc_sRemoteDevInformation_t* SecureElementInfo; -static int secureElementHandle; -extern void *gHWRef; -static int SecureElementTech; -extern uint8_t device_connected_flag; - -namespace android { - -static void com_android_nfc_jni_ioctl_callback ( void* pContext, - phNfc_sData_t* Outparam_Cb, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if (status == NFCSTATUS_SUCCESS ) - { - LOG_CALLBACK("> IOCTL successful",status); - } - else - { - LOG_CALLBACK("> IOCTL error",status); - } - - com_android_nfc_jni_ioctl_buffer = Outparam_Cb; - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); - - com_android_nfc_jni_transceive_buffer = pResBuffer; - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static void com_android_nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if(status==NFCSTATUS_SUCCESS) - { - LOG_CALLBACK("SE Set Mode is Successful",status); - TRACE("SE Handle: %lu", hSecureElement); - } - else - { - LOG_CALLBACK("SE Set Mode is failed\n ",status); - } - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - NFCSTATUS ret; - int i; - JNIEnv *e = nfc_get_env(); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); - } - else - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); - TRACE("Discovered %d secure elements", uNofRemoteDev); - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - bool foundHandle = false; - TRACE("Multiple Protocol supported\n"); - for (i=0; iRemDevType); - if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { - secureElementHandle = psRemoteDevList[i].hTargetDev; - foundHandle = true; - } - } - if (!foundHandle) { - ALOGE("Could not find ISO-DEP secure element"); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - } - else - { - secureElementHandle = psRemoteDevList->hTargetDev; - } - - TRACE("Secure Element Handle: 0x%08x", secureElementHandle); - - /* Set type name */ - jintArray techList; - nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); - - // TODO: Should use the "connected" technology, for now use the first - if ((techList != NULL) && e->GetArrayLength(techList) > 0) { - e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); - TRACE("Store Secure Element Info\n"); - SecureElementInfo = psRemoteDevList->psRemoteDevInfo; - - TRACE("Discovered secure element: tech=%d", SecureElementTech); - } - else { - ALOGE("Discovered secure element, but could not resolve tech"); - status = NFCSTATUS_FAILED; - } - - // This thread may not return to the virtual machine for a long time - // so make sure to delete the local refernce to the tech list. - e->DeleteLocalRef(techList); - } - -clean_and_return: - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - int semResult; - - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - uint8_t Output_Buff[10]; - uint8_t reg_value; - uint8_t mask_value; - struct nfc_jni_callback_data cb_data; - struct nfc_jni_callback_data cb_data_SE_Notification; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) - { - goto clean_and_return; - } - - /* Registery */ - registry_info.MifareUL = TRUE; - registry_info.MifareStd = TRUE; - registry_info.ISO14443_4A = TRUE; - registry_info.ISO14443_4B = TRUE; - registry_info.Jewel = TRUE; - registry_info.Felica = TRUE; - registry_info.NFC = FALSE; - - CONCURRENCY_LOCK(); - - TRACE("Open Secure Element"); - - /* Check if NFC device is already connected to a tag or P2P peer */ - if (device_connected_flag == 1) - { - ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); - goto clean_and_return; - } - - /* Test if External RF field is detected */ - InParam.buffer = ExternalRFDetected; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - /* Check the value */ - reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; - mask_value = reg_value & 0x40; - - if(mask_value == 0x40) - { - // There is an external RF field present, fail the open request - ALOGD("Unable to open SE connection, external RF Field detected"); - goto clean_and_return; - } - - /* Get Secure Element List */ - TRACE("phLibNfc_SE_GetSecureElementList()"); - ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); - if (ret == NFCSTATUS_SUCCESS) - { - TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i SMX detected"); - TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); - /* save SMARTMX index */ - SmartMX_detected = 1; - SmartMX_index = i; - } - } - - if(SmartMX_detected) - { - REENTRANCE_LOCK(); - TRACE("phLibNfc_RemoteDev_NtfRegister()"); - ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, - com_android_nfc_jni_open_secure_element_notification_callback, - (void *)&cb_data_SE_Notification); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("Register Notification error"); - goto clean_and_return; - } - - /* Set wired mode */ - REENTRANCE_LOCK(); - TRACE("phLibNfc_SE_SetMode: Wired mode"); - ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, - phLibNfc_SE_ActModeWired, - com_android_nfc_jni_smartMX_setModeCb, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING ) - { - ALOGE("\n> SE Set SmartMX mode ERROR \n" ); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("SE set mode failed"); - goto clean_and_return; - } - - TRACE("Waiting for notification"); - /* Wait for callback response */ - if(sem_wait(&cb_data_SE_Notification.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && - cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) - { - ALOGE("SE detection failed"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Connect Tag */ - CONCURRENCY_LOCK(); - TRACE("phLibNfc_RemoteDev_Connect(SMX)"); - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("CONNECT semaphore error"); - goto clean_and_return; - } - - /* Connect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Secure Element connect error"); - goto clean_and_return; - } - - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue | 0x40); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - /* Return the Handle of the SecureElement */ - return secureElementHandle; - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); - goto clean_and_return; - } - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - CONCURRENCY_UNLOCK(); - return 0; -} - - -static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) -{ - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - uint32_t SmartMX_Handle; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t Output_Buff[10]; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Close Secure element function "); - - CONCURRENCY_LOCK(); - /* Disconnect */ - TRACE("Disconnecting from SMX (handle = 0x%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, - NFC_SMARTMX_RELEASE, - com_android_nfc_jni_disconnect_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("\n> Disconnect SE ERROR \n" ); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue & 0xBF); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, - jobject o,jint handle, jbyteArray data) -{ - uint8_t offset = 0; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - - int tech = SecureElementTech; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Exchange APDU function "); - - CONCURRENCY_LOCK(); - - TRACE("Secure Element tech: %d\n", tech); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - /* Prepare transceive info structure */ - if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) - { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - else if(tech == TARGET_TYPE_ISO14443_4) - { - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - } - - transceive_info.sSendData.buffer = buf + offset; - transceive_info.sSendData.length = buflen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - com_android_nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("TRANSCEIVE semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("TRANSCEIVE error"); - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); - if(result != NULL) - { - e->SetByteArrayRegion(result, 0, - com_android_nfc_jni_transceive_buffer->length, - (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) -{ - TRACE("Get Secure element UID function "); - jbyteArray SecureElementUid; - - if(handle == secureElementHandle) - { - SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); - e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); - return SecureElementUid; - } - else - { - return NULL; - } -} - -static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) -{ - jintArray techList; - TRACE("Get Secure element Type function "); - - if(handle == secureElementHandle) - { - techList = e->NewIntArray(1); - e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); - return techList; - } - else - { - return NULL; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doNativeOpenSecureElementConnection", "()I", - (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, - {"doNativeDisconnectSecureElementConnection", "(I)Z", - (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, - {"doTransceive", "(I[B)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, - {"doGetUid", "(I)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, - {"doGetTechList", "(I)[I", - (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, -}; - -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp deleted file mode 100644 index dbf8dc9..0000000 --- a/nxp/jni/com_android_nfc_NativeNfcTag.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" -#include "phNfcHalTypes.h" - -static phLibNfc_Data_t nfc_jni_ndef_rw; -static phLibNfc_Handle handle; -uint8_t *nfc_jni_ndef_buf = NULL; -uint32_t nfc_jni_ndef_buf_len = 0; - -extern uint8_t device_connected_flag; - -namespace android { - -extern phLibNfc_Handle storedHandle; - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); -extern void nfc_jni_reset_timeout_values(); - -/* - * Callbacks - */ - static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_tag_rw_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - if (pCallbackData->pContext != NULL) { - // Store the remote dev info ptr in the callback context - // Note that this ptr will remain valid, it is tied to a statically - // allocated buffer in libnfc. - phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = - (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; - *ppRemoteDevInfo = psRemoteDevInfo; - } - - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_checkndef_callback(void *pContext, - phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_checkndef_callback", status); - phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); - if(status == NFCSTATUS_OK) - { - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; - nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); - if (pNdefInfo != NULL) *pNdefInfo = info; - } - else { - if (pNdefInfo != NULL) { - memset(pNdefInfo, 0, sizeof(*pNdefInfo)); - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_async_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; -} - -static phNfc_sData_t *nfc_jni_transceive_buffer; - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - nfc_jni_transceive_buffer = pResBuffer; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presencecheck_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_formatndef_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_readonly_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* Functions */ -static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, - jobject o) -{ - NFCSTATUS status; - phLibNfc_Handle handle = 0; - jbyteArray buf = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; - nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; - - TRACE("phLibNfc_Ndef_Read()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, - phLibNfc_Ndef_EBegin, - nfc_jni_tag_rw_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - buf = e->NewByteArray(nfc_jni_ndef_rw.length); - e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, - (jbyte *)nfc_jni_ndef_rw.buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - - return buf; -} - - -static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, - jobject o, jbyteArray buf) -{ - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); - nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_Ndef_Write()"); - TRACE("Ndef Handle :0x%x\n",handle); - TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * Utility to recover poll bytes from target infos - */ -static void set_target_pollBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); - - jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingPollBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - jint *techId = e->GetIntArrayElements(techList, 0); - int techListLength = e->GetArrayLength(techList); - - jbyteArray pollBytes = e->NewByteArray(0); - jobjectArray techPollBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(pollBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) - { - /* ISO14443-3A: ATQA/SENS_RES */ - case TARGET_TYPE_ISO14443_3A: - if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { - // Jewel ATQA is not read and stored by the PN544, but it is fixed - // at {0x00, 0x0C} in the spec. So eJewel can safely be - // translated to {0x00, 0x0C}. - const static jbyte JewelAtqA[2] = {0x00, 0x0C}; - pollBytes = e->NewByteArray(2); - e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); - } - else { - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); - } - break; - /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ - case TARGET_TYPE_ISO14443_3B: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); - break; - /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ - case TARGET_TYPE_FELICA: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - pollBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techPollBytes, tech, pollBytes); - } - - e->SetObjectField(tag, f, techPollBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); - -} - -/* - * Utility to recover activation bytes from target infos - */ -static void set_target_activationBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - - jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); - jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingActBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - int techListLength = e->GetArrayLength(techList); - jint *techId = e->GetIntArrayElements(techList, 0); - - jbyteArray actBytes = e->NewByteArray(0); - jobjectArray techActBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(actBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) { - - /* ISO14443-3A: SAK/SEL_RES */ - case TARGET_TYPE_ISO14443_3A: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); - break; - /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ - /* ISO14443-3B & ISO14443-4: HiLayerResp */ - case TARGET_TYPE_ISO14443_4: - // Determine whether -A or -B - if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); - e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); - } - else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); - e->SetByteArrayRegion(actBytes, 0, - psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); - } - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - actBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techActBytes, tech, actBytes); - } - e->SetObjectField(tag, f, techActBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); -} - -static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - // Success, set poll & act bytes - set_target_pollBytes(e, o, pRemDevInfo); - set_target_activationBytes(e, o, pRemDevInfo); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, - jobject o) -{ - // Reconnect is provided by libnfc by just calling connect again - // on the same handle. - int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - if (libNfcType != -1) { - // Note that some tag types are stateless, hence we do not reconnect - // those. Currently those are the Jewel and Iso15693 technologies. - if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); - return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); - } - else { - return NFCSTATUS_SUCCESS; - } - } - else { - return NFCSTATUS_REJECTED; - } -} - - -static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_connected_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Reset the stored handle */ - storedHandle = 0; - - nfc_jni_reset_timeout_values(); - - /* Disconnect */ - TRACE("Disconnecting from tag (%x)", handle); - - if (handle == -1) { - // Was never connected to any tag, exit - result = JNI_TRUE; - ALOGE("doDisconnect() - Target already disconnected"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, - nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - result = JNI_TRUE; - TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); - goto clean_and_return; - } - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static uint16_t -crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) -{ - uint16_t b, crc = init; - - do { - b = *msg++ ^ (crc & 0xFF); - b ^= (b << 4) & 0xFF; - crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); - } while( --len ); - - return crc; -} - -static void -nfc_insert_crc_a( uint8_t* msg, size_t len ) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - msg[len] = crc & 0xFF; - msg[len + 1] = (crc >> 8) & 0xFF; -} - -static void -nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - *byte1 = crc & 0xFF; - *byte2 = (crc >> 8) & 0xFF; -} - -static bool -crc_valid( uint8_t* msg, size_t len) -{ - uint8_t crcByte1, crcByte2; - - nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, - len - 2, &crcByte1, &crcByte2); - - if (msg[len - 2] == crcByte1 && - msg[len - 1] == crcByte2) { - return true; - } - else { - return false; - } - -} - -static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, - jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) -{ - uint8_t offset = 0; - // buf is the pointer to the JNI array and never overwritten, - // outbuf is passed into the transceive - it may be pointed to new memory - // to be extended with CRC. - uint8_t *buf = NULL; - uint32_t buflen; - - uint8_t *outbuf = NULL; - uint32_t outlen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - int selectedTech = 0; - int selectedLibNfcType = 0; - jint* technologies = NULL; - bool checkResponseCrc = false; - - jint *targetLost; - if (statusTargetLost != NULL) { - targetLost = e->GetIntArrayElements(statusTargetLost, 0); - if (targetLost != NULL) { - *targetLost = 0; - } - } else { - targetLost = NULL; - } - - memset(&transceive_info, 0, sizeof(transceive_info)); - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - selectedTech = nfc_jni_get_connected_technology(e, o); - selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - - buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = outlen = (uint32_t)e->GetArrayLength(data); - - switch (selectedTech) { - case TARGET_TYPE_FELICA: - transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - if (raw) { - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - break; - case TARGET_TYPE_ISO14443_3A: - // Check which libnfc type - if (selectedLibNfcType == phNfc_eJewel_PICC) { - // For the Jewel pipe, CRC is automatically computed - transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; - transceive_info.addr = 0; - } else { - if (raw) { - // Use Mifare Raw to implement a standard - // ISO14443-3A transceive, with CRC added - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - // Use the mifare pipe - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - - } - break; - case TARGET_TYPE_ISO14443_4: - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_ISO15693: - transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; - transceive_info.addr = 0; - break; - case TARGET_TYPE_UNKNOWN: - case TARGET_TYPE_ISO14443_3B: - // Not supported - goto clean_and_return; - default: - break; - } - - transceive_info.sSendData.buffer = outbuf + offset; - transceive_info.sSendData.length = outlen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - - /* Copy results back to Java * - * In case of NfcA and raw, also check the CRC in the response - * and cut it off in the returned data. - */ - if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { - if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { - result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length - 2, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } - } else { - result = e->NewByteArray(nfc_jni_transceive_buffer->length); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - if ((outbuf != buf) && (outbuf != NULL)) { - // Buf was extended and re-alloced with crc bytes, free separately - free(outbuf); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)buf, JNI_ABORT); - - if (targetLost != NULL) { - e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); - } - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, - jint libnfcType, jint javaType) -{ - jint ndefType = NDEF_UNKNOWN_TYPE; - - switch (libnfcType) { - case phNfc_eJewel_PICC: - ndefType = NDEF_TYPE1_TAG; - break; - case phNfc_eISO14443_3A_PICC: - ndefType = NDEF_TYPE2_TAG;; - break; - case phNfc_eFelica_PICC: - ndefType = NDEF_TYPE3_TAG; - break; - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - ndefType = NDEF_TYPE4_TAG; - break; - case phNfc_eMifare_PICC: - if (javaType == TARGET_TYPE_MIFARE_UL) { - ndefType = NDEF_TYPE2_TAG; - } else { - ndefType = NDEF_MIFARE_CLASSIC_TAG; - } - break; - case phNfc_eISO15693_PICC: - ndefType = NDEF_ICODE_SLI_TAG; - break; - default: - ndefType = NDEF_UNKNOWN_TYPE; - break; - } - return ndefType; -} - -static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) -{ - phLibNfc_Handle handle = 0; - jint status; - phLibNfc_ChkNdef_Info_t sNdefInfo; - struct nfc_jni_callback_data cb_data; - jint *ndef = e->GetIntArrayElements(ndefinfo, 0); - int apiCardState = NDEF_MODE_UNKNOWN; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - cb_data.pContext = &sNdefInfo; - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_Ndef_CheckNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); - - if (status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ndef[0] = sNdefInfo.MaxNdefMsgLength; - // Translate the card state to know values for the NFC API - switch (sNdefInfo.NdefCardState) { - case PHLIBNFC_NDEF_CARD_INITIALISED: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_READ_ONLY: - apiCardState = NDEF_MODE_READ_ONLY; - break; - case PHLIBNFC_NDEF_CARD_READ_WRITE: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_INVALID: - apiCardState = NDEF_MODE_UNKNOWN; - break; - } - ndef[1] = apiCardState; - -clean_and_return: - e->ReleaseIntArrayElements(ndefinfo, ndef, 0); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_RemoteDev_CheckPresence()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, - jobject o, jbyteArray pollBytes, jbyteArray actBytes) -{ - // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire - // is supported. - jboolean result = JNI_FALSE; - - // DESfire has one sak byte and 2 ATQA bytes - if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && - actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { - jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); - jbyte* act = e->GetByteArrayElements(actBytes, NULL); - if (act[0] == 0x20 && poll[1] == 0x03) { - uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; - // Identifies as DESfire, use get version cmd to be sure - jbyteArray versionCmd = e->NewByteArray(5); - e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); - jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, - versionCmd, JNI_TRUE, NULL); - if (respBytes != NULL) { - // Check whether the response matches a typical DESfire - // response. - // libNFC even does more advanced checking than we do - // here, and will only format DESfire's with a certain - // major/minor sw version and NXP as a manufacturer. - // We don't want to do such checking here, to avoid - // having to change code in multiple places. - // A succesful (wrapped) DESFire getVersion command returns - // 9 bytes, with byte 7 0x91 and byte 8 having status - // code 0xAF (these values are fixed and well-known). - int respLength = e->GetArrayLength(respBytes); - jbyte* resp = e->GetByteArrayElements(respBytes, NULL); - if (respLength == 9 && resp[7] == (jbyte)0x91 && - resp[8] == (jbyte)0xAF) { - result = JNI_TRUE; - } - e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); - } - } - e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); - e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); - } - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - phNfc_sData_t keyBuffer; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_RemoteDev_FormatNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t keyBuffer; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_ConvertToReadOnlyNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeNfcTag_doDisconnect}, - {"doReconnect", "()I", - (void *)com_android_nfc_NativeNfcTag_doReconnect}, - {"doHandleReconnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, - {"doTransceive", "([BZ[I)[B", - (void *)com_android_nfc_NativeNfcTag_doTransceive}, - {"doGetNdefType", "(II)I", - (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, - {"doCheckNdef", "([I)I", - (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, - {"doRead", "()[B", - (void *)com_android_nfc_NativeNfcTag_doRead}, - {"doWrite", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doWrite}, - {"doPresenceCheck", "()Z", - (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, - {"doIsIsoDepNdefFormatable", "([B[B)Z", - (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, - {"doNdefFormat", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, - {"doMakeReadonly", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, -}; - -int register_com_android_nfc_NativeNfcTag(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp deleted file mode 100644 index b3cc6e3..0000000 --- a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp +++ /dev/null @@ -1,490 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -extern uint8_t device_connected_flag; - -namespace android { - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); - -/* - * Callbacks - */ -static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presence_check_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; - psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_receive_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - *ptr = data; - } - else - { - *ptr = NULL; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Functions - */ - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - /* Report the callback data and wake up the caller */ - pCallbackData->pContext = pResBuffer; - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - jclass target_cls = NULL; - jobject tag; - jmethodID ctor; - jfieldID f; - jbyteArray generalBytes = NULL; - phNfc_sData_t sGeneralBytes; - unsigned int i; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Set General Bytes */ - target_cls = e->GetObjectClass(o); - - f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes Length = %d", sGeneralBytes.length); - TRACE("General Bytes ="); - for(i=0;iNewByteArray(sGeneralBytes.length); - - e->SetByteArrayRegion(generalBytes, 0, - sGeneralBytes.length, - (jbyte *)sGeneralBytes.buffer); - - e->SetObjectField(o, f, generalBytes); - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - /* Restart the polling loop if the connection failed */ - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jboolean result = JNI_FALSE; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Disconnect */ - TRACE("Disconnecting from target (handle = 0x%x)", handle); - - /* NativeNfcTag waits for tag to leave the field here with presence check. - * We do not in P2P path because presence check is not safe while transceive may be - * in progress. - */ - - TRACE("phLibNfc_RemoteDev_Disconnect()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); - } - else - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, - jobject o, jbyteArray data) -{ - NFCSTATUS status; - uint8_t offset = 2; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - phNfc_sData_t * receive_buffer = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) - { - goto clean_and_return; - } - - /* Transceive*/ - TRACE("Transceive data to target (handle = 0x%x)", handle); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - TRACE("Buffer Length = %d\n", buflen); - - transceive_info.sSendData.buffer = buf; //+ offset; - transceive_info.sSendData.length = buflen; //- offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(receive_buffer->length); - if(result != NULL) - e->SetByteArrayRegion(result, 0, - receive_buffer->length, - (jbyte *)receive_buffer->buffer); - -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - - -static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( - JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct timespec ts; - phLibNfc_Handle handle; - jbyteArray buf = NULL; - static phNfc_sData_t *data; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)data)) - { - goto clean_and_return; - } - - /* Receive */ - TRACE("phLibNfc_RemoteDev_Receive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(data == NULL) - { - goto clean_and_return; - } - - buf = e->NewByteArray(data->length); - e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return buf; -} - -static jboolean com_android_nfc_NativeP2pDevice_doSend( - JNIEnv *e, jobject o, jbyteArray buf) -{ - NFCSTATUS status; - phNfc_sData_t data; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Send */ - TRACE("Send data to the Initiator (handle = 0x%x)", handle); - - data.length = (uint32_t)e->GetArrayLength(buf); - data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_RemoteDev_Send()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, - {"doTransceive", "([B)[B", - (void *)com_android_nfc_NativeP2pDevice_doTransceive}, - {"doReceive", "()[B", - (void *)com_android_nfc_NativeP2pDevice_doReceive}, - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeP2pDevice_doSend}, -}; - -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", - gMethods, NELEM(gMethods)); -} - -} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp deleted file mode 100644 index f0487d3..0000000 --- a/nxp/jni/com_android_nfc_list.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#undef LOG_TAG -#define LOG_TAG "NFC_LIST" - -bool listInit(listHead* pList) -{ - pList->pFirst = NULL; - if(pthread_mutex_init(&pList->mutex, NULL) == -1) - { - ALOGE("Mutex creation failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listDestroy(listHead* pList) -{ - bool bListNotEmpty = true; - while (bListNotEmpty) { - bListNotEmpty = listGetAndRemoveNext(pList, NULL); - } - - if(pthread_mutex_destroy(&pList->mutex) == -1) - { - ALOGE("Mutex destruction failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listAdd(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pLastNode; - bool result; - - /* Create node */ - pNode = (struct listNode*)malloc(sizeof(listNode)); - if (pNode == NULL) - { - result = false; - ALOGE("Failed to malloc"); - goto clean_and_return; - } - TRACE("Allocated node: %8p (%8p)", pNode, pData); - pNode->pData = pData; - pNode->pNext = NULL; - - pthread_mutex_lock(&pList->mutex); - - /* Add the node to the list */ - if (pList->pFirst == NULL) - { - /* Set the node as the head */ - pList->pFirst = pNode; - } - else - { - /* Seek to the end of the list */ - pLastNode = pList->pFirst; - while(pLastNode->pNext != NULL) - { - pLastNode = pLastNode->pNext; - } - - /* Add the node to the current list */ - pLastNode->pNext = pNode; - } - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listRemove(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pRemovedNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst == NULL) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - pNode = pList->pFirst; - if (pList->pFirst->pData == pData) - { - /* Get the removed node */ - pRemovedNode = pNode; - - /* Remove the first node */ - pList->pFirst = pList->pFirst->pNext; - } - else - { - while (pNode->pNext != NULL) - { - if (pNode->pNext->pData == pData) - { - /* Node found ! */ - break; - } - pNode = pNode->pNext; - } - - if (pNode->pNext == NULL) - { - /* Node not found */ - result = false; - ALOGE("Failed to deallocate (not found %8p)", pData); - goto clean_and_return; - } - - /* Get the removed node */ - pRemovedNode = pNode->pNext; - - /* Remove the node from the list */ - pNode->pNext = pNode->pNext->pNext; - } - - /* Deallocate the node */ - TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); - free(pRemovedNode); - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listGetAndRemoveNext(listHead* pList, void** ppData) -{ - struct listNode* pNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - /* Work on the first node */ - pNode = pList->pFirst; - - /* Return the data */ - if (ppData != NULL) - { - *ppData = pNode->pData; - } - - /* Remove and deallocate the node */ - pList->pFirst = pNode->pNext; - TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); - free(pNode); - - result = true; - -clean_and_return: - listDump(pList); - pthread_mutex_unlock(&pList->mutex); - return result; -} - -void listDump(listHead* pList) -{ - struct listNode* pNode = pList->pFirst; - - TRACE("Node dump:"); - while (pNode != NULL) - { - TRACE("- %8p (%8p)", pNode, pNode->pData); - pNode = pNode->pNext; - } -} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h deleted file mode 100644 index 22b4f09..0000000 --- a/nxp/jni/com_android_nfc_list.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_LIST_H__ -#define __COM_ANDROID_NFC_LIST_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct listNode -{ - void* pData; - struct listNode* pNext; -}; - -struct listHead -{ - listNode* pFirst; - pthread_mutex_t mutex; -}; - -bool listInit(listHead* pList); -bool listDestroy(listHead* pList); -bool listAdd(listHead* pList, void* pData); -bool listRemove(listHead* pList, void* pData); -bool listGetAndRemoveNext(listHead* pList, void** ppData); -void listDump(listHead* pList); - -#ifdef __cplusplus -} -#endif - -#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index db78496..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java deleted file mode 100755 index 3a7e57f..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java deleted file mode 100755 index 69506c5..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java deleted file mode 100755 index f969627..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java deleted file mode 100755 index e2d91ec..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java deleted file mode 100755 index eddde94..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java deleted file mode 100755 index 094f46a..0000000 --- a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.dhimpl; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 3e7a6b5..602b25d 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.dhimpl.NativeNfcManager; -import com.android.nfc.dhimpl.NativeNfcSecureElement; +import com.android.nfc.nxp.NativeNfcManager; +import com.android.nfc.nxp.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; diff --git a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..c9d3b5d --- /dev/null +++ b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..531afd8 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java new file mode 100755 index 0000000..a337d35 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java new file mode 100755 index 0000000..4bd8c24 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java new file mode 100755 index 0000000..88f9b9d --- /dev/null +++ b/src/com/android/nfc/nxp/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java new file mode 100755 index 0000000..8996dfb --- /dev/null +++ b/src/com/android/nfc/nxp/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java new file mode 100755 index 0000000..7c7db41 --- /dev/null +++ b/src/com/android/nfc/nxp/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.nxp; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} -- cgit v1.1 From 4b33b45ed7880968f9836213e2395dbd55e17b31 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 25 Jul 2012 08:56:11 -0700 Subject: Move NXP JNI and DeviceHost implementation into separate dir. (DO NOT MERGE) Preparation for the new NCI stack. The idea is to build either the NXP or the NCI stack, triggered by a makefile switch. To that end, move the DeviceHost and JNI implementations in their own directory, so we can build them only if needed. Change-Id: I8579ec30ceb1908e4cd180cfbd10224aa4bddb8d --- Android.mk | 8 + jni/Android.mk | 35 - jni/com_android_nfc.cpp | 564 ----- jni/com_android_nfc.h | 259 -- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 -- jni/com_android_nfc_NativeLlcpServiceSocket.cpp | 227 -- jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ---- jni/com_android_nfc_NativeNfcManager.cpp | 2622 -------------------- jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ------ jni/com_android_nfc_NativeNfcTag.cpp | 1255 ---------- jni/com_android_nfc_NativeP2pDevice.cpp | 490 ---- jni/com_android_nfc_list.cpp | 210 -- jni/com_android_nfc_list.h | 49 - nxp/Android.mk | 3 + nxp/jni/Android.mk | 35 + nxp/jni/com_android_nfc.cpp | 564 +++++ nxp/jni/com_android_nfc.h | 259 ++ ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 253 ++ .../com_android_nfc_NativeLlcpServiceSocket.cpp | 227 ++ nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 468 ++++ nxp/jni/com_android_nfc_NativeNfcManager.cpp | 2622 ++++++++++++++++++++ nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 770 ++++++ nxp/jni/com_android_nfc_NativeNfcTag.cpp | 1255 ++++++++++ nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 490 ++++ nxp/jni/com_android_nfc_list.cpp | 210 ++ nxp/jni/com_android_nfc_list.h | 49 + .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 + .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 + .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 373 +++ .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 + nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 803 ++++++ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 + src/com/android/nfc/NfcService.java | 4 +- .../nfc/nxp/NativeLlcpConnectionlessSocket.java | 78 - .../android/nfc/nxp/NativeLlcpServiceSocket.java | 53 - src/com/android/nfc/nxp/NativeLlcpSocket.java | 99 - src/com/android/nfc/nxp/NativeNfcManager.java | 373 --- .../android/nfc/nxp/NativeNfcSecureElement.java | 67 - src/com/android/nfc/nxp/NativeNfcTag.java | 803 ------ src/com/android/nfc/nxp/NativeP2pDevice.java | 77 - 41 files changed, 8765 insertions(+), 8754 deletions(-) delete mode 100644 jni/Android.mk delete mode 100644 jni/com_android_nfc.cpp delete mode 100644 jni/com_android_nfc.h delete mode 100644 jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpServiceSocket.cpp delete mode 100644 jni/com_android_nfc_NativeLlcpSocket.cpp delete mode 100644 jni/com_android_nfc_NativeNfcManager.cpp delete mode 100755 jni/com_android_nfc_NativeNfcSecureElement.cpp delete mode 100644 jni/com_android_nfc_NativeNfcTag.cpp delete mode 100644 jni/com_android_nfc_NativeP2pDevice.cpp delete mode 100644 jni/com_android_nfc_list.cpp delete mode 100644 jni/com_android_nfc_list.h create mode 100644 nxp/Android.mk create mode 100644 nxp/jni/Android.mk create mode 100644 nxp/jni/com_android_nfc.cpp create mode 100644 nxp/jni/com_android_nfc.h create mode 100644 nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeLlcpSocket.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcManager.cpp create mode 100755 nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp create mode 100644 nxp/jni/com_android_nfc_NativeNfcTag.cpp create mode 100644 nxp/jni/com_android_nfc_NativeP2pDevice.cpp create mode 100644 nxp/jni/com_android_nfc_list.cpp create mode 100644 nxp/jni/com_android_nfc_list.h create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java create mode 100755 nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpServiceSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeLlcpSocket.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcManager.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcSecureElement.java delete mode 100755 src/com/android/nfc/nxp/NativeNfcTag.java delete mode 100755 src/com/android/nfc/nxp/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index a041854..2cdfc68 100644 --- a/Android.mk +++ b/Android.mk @@ -6,6 +6,14 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) +ifeq ($(NFC_USE_NCI_STACK), true) + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nci) +else + LOCAL_SRC_FILES += \ + $(call all-java-files-under, nxp) +endif + LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform diff --git a/jni/Android.mk b/jni/Android.mk deleted file mode 100644 index 8ae792a..0000000 --- a/jni/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - - - -LOCAL_SRC_FILES:= \ - com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ - com_android_nfc_NativeLlcpServiceSocket.cpp \ - com_android_nfc_NativeLlcpSocket.cpp \ - com_android_nfc_NativeNfcManager.cpp \ - com_android_nfc_NativeNfcTag.cpp \ - com_android_nfc_NativeP2pDevice.cpp \ - com_android_nfc_NativeNfcSecureElement.cpp \ - com_android_nfc_list.cpp \ - com_android_nfc.cpp - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) \ - external/libnfc-nxp/src \ - external/libnfc-nxp/inc - -LOCAL_SHARED_LIBRARIES := \ - libnativehelper \ - libcutils \ - libutils \ - libnfc \ - libhardware - -#LOCAL_CFLAGS += -O0 -g - -LOCAL_MODULE := libnfc_jni -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp deleted file mode 100644 index d794d6e..0000000 --- a/jni/com_android_nfc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "errno.h" -#include "com_android_nfc.h" -#include "com_android_nfc_list.h" -#include "phLibNfcStatus.h" - -/* - * JNI Initialization - */ -jint JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - JNIEnv *e; - - ALOGD("NFC Service : loading JNI\n"); - - // Check JNI version - if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) - return JNI_ERR; - - android::vm = jvm; - - if (android::register_com_android_nfc_NativeNfcManager(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcTag(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) - return JNI_ERR; - if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) - return JNI_ERR; - - return JNI_VERSION_1_6; -} - -namespace android { - -extern struct nfc_jni_native_data *exported_nat; - -JavaVM *vm; - -/* - * JNI Utils - */ -JNIEnv *nfc_get_env() -{ - JNIEnv *e; - if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { - ALOGE("Current thread is not attached to VM"); - phLibNfc_Mgt_Recovery(); - abort(); - } - return e; -} - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) -{ - /* Create semaphore */ - if(sem_init(&pCallbackData->sem, 0, 0) == -1) - { - ALOGE("Semaphore creation failed (errno=0x%08x)", errno); - return false; - } - - /* Set default status value */ - pCallbackData->status = NFCSTATUS_FAILED; - - /* Copy the context */ - pCallbackData->pContext = pContext; - - /* Add to active semaphore list */ - if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to add the semaphore to the list"); - } - - return true; -} - -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) -{ - /* Destroy semaphore */ - if (sem_destroy(&pCallbackData->sem)) - { - ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); - } - - /* Remove from active semaphore list */ - if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) - { - ALOGE("Failed to remove semaphore from the list"); - } - -} - -void nfc_cb_data_releaseAll() -{ - nfc_jni_callback_data* pCallbackData; - - while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) - { - pCallbackData->status = NFCSTATUS_FAILED; - sem_post(&pCallbackData->sem); - } -} - -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj) -{ - jclass cls; - jobject obj; - jmethodID ctor; - - cls = e->FindClass(clsname); - if(cls == NULL) - { - return -1; - ALOGD("Find class error\n"); - } - - - ctor = e->GetMethodID(cls, "", "()V"); - - obj = e->NewObject(cls, ctor); - if(obj == NULL) - { - return -1; - ALOGD("Create object error\n"); - } - - *cached_obj = e->NewGlobalRef(obj); - if(*cached_obj == NULL) - { - e->DeleteLocalRef(obj); - ALOGD("Global ref error\n"); - return -1; - } - - e->DeleteLocalRef(obj); - - return 0; -} - - -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - /* Retrieve native structure address */ - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mNative", "I"); - return (struct nfc_jni_native_data*)e->GetIntField(o, f); -} - -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) -{ - return exported_nat; -} - -static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; - -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) -{ - - pthread_mutexattr_t recursive_attr; - - pthread_mutexattr_init(&recursive_attr); - pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); - - if(nfc_jni_native_monitor == NULL) - { - nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); - } - - if(nfc_jni_native_monitor != NULL) - { - memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); - - if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) - { - ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) - { - ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); - return NULL; - } - - if(!listInit(&nfc_jni_native_monitor->sem_list)) - { - ALOGE("NFC Manager Semaphore List creation failed"); - return NULL; - } - - LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); - - if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) - { - ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); - return NULL; - } - - if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) - { - ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); - return NULL; - } - -} - - return nfc_jni_native_monitor; -} - -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) -{ - return nfc_jni_native_monitor; -} - - -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mMode", "S"); - - return e->GetShortField(o, f); -} - - -int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) -{ - - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedTechIndex", "I"); - - return e->GetIntField(o, f); - -} - -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - int connectedTech = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); - - if ((connectedTechIndex != -1) && (techTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(techTypes))) { - jint* technologies = e->GetIntArrayElements(techTypes, 0); - if (technologies != NULL) { - connectedTech = technologies[connectedTechIndex]; - e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); - } - } - - return connectedTech; - -} - -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jint connectedLibNfcType = -1; - - int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); - jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); - - if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && - (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { - jint* types = e->GetIntArrayElements(libNfcTypes, 0); - if (types != NULL) { - connectedLibNfcType = types[connectedTechIndex]; - e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); - } - } - return connectedLibNfcType; - -} - -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mConnectedHandle", "I"); - - return e->GetIntField(o, f); -} - -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mHandle", "I"); - - return e->GetIntField(o, f); -} - -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) -{ - jclass c; - jfieldID f; - jintArray techtypes; - - c = e->GetObjectClass(o); - f = e->GetFieldID(c, "mTechList","[I"); - - /* Read the techtypes */ - techtypes = (jintArray) e->GetObjectField(o, f); - - return techtypes; -} - - - -//Display status code -const char* nfc_jni_get_status_name(NFCSTATUS status) -{ - #define STATUS_ENTRY(status) { status, #status } - - struct status_entry { - NFCSTATUS code; - const char *name; - }; - - const struct status_entry sNameTable[] = { - STATUS_ENTRY(NFCSTATUS_SUCCESS), - STATUS_ENTRY(NFCSTATUS_FAILED), - STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), - STATUS_ENTRY(NFCSTATUS_TARGET_LOST), - STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), - STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), - STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_SHUTDOWN), - STATUS_ENTRY(NFCSTATUS_ABORTED), - STATUS_ENTRY(NFCSTATUS_REJECTED ), - STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), - STATUS_ENTRY(NFCSTATUS_PENDING), - STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), - STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), - STATUS_ENTRY(NFCSTATUS_BUSY), - STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), - STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), - STATUS_ENTRY(NFCSTATUS_DESELECTED), - STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), - STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), - STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), - STATUS_ENTRY(NFCSTATUS_RF_ERROR), - STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), - STATUS_ENTRY(NFCSTATUS_INVALID_STATE), - STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), - STATUS_ENTRY(NFCSTATUS_RELEASED), - STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), - STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), - STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), - STATUS_ENTRY(NFCSTATUS_READ_FAILED), - STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), - STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), - STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), - STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), - STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), - STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), - STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), - }; - - int i = sizeof(sNameTable)/sizeof(status_entry); - - while(i>0) - { - i--; - if (sNameTable[i].code == PHNFCSTATUS(status)) - { - return sNameTable[i].name; - } - } - - return "UNKNOWN"; -} - -int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, - int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { - bool found = false; - for (int i = 0; i < listSize; i++) { - if (techList[i] == techToAdd) { - found = true; - break; - } - } - if (!found && listSize < maxListSize) { - techList[listSize] = techToAdd; - handleList[listSize] = handleToAdd; - typeList[listSize] = typeToAdd; - return listSize + 1; - } - else { - return listSize; - } -} - - -#define MAX_NUM_TECHNOLOGIES 32 - -/* - * Utility to get a technology tree and a corresponding handle list from a detected tag. - */ -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* libnfcTypeList) -{ - int technologies[MAX_NUM_TECHNOLOGIES]; - int handles[MAX_NUM_TECHNOLOGIES]; - int libnfctypes[MAX_NUM_TECHNOLOGIES]; - - int index = 0; - // TODO: This counts from up to down because on multi-protocols, the - // ISO handle is usually the second, and we prefer the ISO. Should implement - // a method to find the "preferred handle order" and use that instead, - // since we shouldn't have dependencies on the tech list ordering. - for (int target = count - 1; target >= 0; target--) { - int type = devList[target].psRemoteDevInfo->RemDevType; - int handle = devList[target].hTargetDev; - switch (type) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - break; - } - case phNfc_eISO14443_4B_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, index, - MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO14443_3A_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - case phNfc_eISO14443_B_PICC: - { - // TODO a bug in libnfc will cause 14443-3B only cards - // to be returned as this type as well, but these cards - // are very rare. Hence assume it's -4B - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); - }break; - case phNfc_eISO15693_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); - }break; - case phNfc_eMifare_PICC: - { - // We don't want to be too clever here; libnfc has already determined - // it's a Mifare, so we only check for UL, for all other tags - // we assume it's a mifare classic. This should make us more - // future-proof. - int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; - switch(sak) - { - case 0x00: - // could be UL or UL-C - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); - break; - default: - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); - break; - } - }break; - case phNfc_eFelica_PICC: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); - }break; - case phNfc_eJewel_PICC: - { - // Jewel represented as NfcA - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); - }break; - default: - { - index = addTechIfNeeded(technologies, handles, libnfctypes, - index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); - } - } - } - - // Build the Java arrays - if (techList != NULL) { - *techList = e->NewIntArray(index); - e->SetIntArrayRegion(*techList, 0, index, technologies); - } - - if (handleList != NULL) { - *handleList = e->NewIntArray(index); - e->SetIntArrayRegion(*handleList, 0, index, handles); - } - - if (libnfcTypeList != NULL) { - *libnfcTypeList = e->NewIntArray(index); - e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); - } -} - -} // namespace android diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h deleted file mode 100644 index a44bcf0..0000000 --- a/jni/com_android_nfc.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_JNI_H__ -#define __COM_ANDROID_NFC_JNI_H__ - -#define LOG_TAG "NFCJNI" - -#include -#include - -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include - -} -#include // for property_get - - -/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ -#define DISCOVERY_MODE_TAG_READER 0 -#define DISCOVERY_MODE_NFCIP1 1 -#define DISCOVERY_MODE_CARD_EMULATION 2 - -#define DISCOVERY_MODE_TABLE_SIZE 3 - -#define DISCOVERY_MODE_DISABLED 0 -#define DISCOVERY_MODE_ENABLED 1 - -#define MODE_P2P_TARGET 0 -#define MODE_P2P_INITIATOR 1 - -/* Properties values */ -#define PROPERTY_LLCP_LTO 0 -#define PROPERTY_LLCP_MIU 1 -#define PROPERTY_LLCP_WKS 2 -#define PROPERTY_LLCP_OPT 3 -#define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 -#define PROPERTY_NFC_DISCOVERY_F 6 -#define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 - -/* Error codes */ -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -/* Pre-defined card read/write state values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_UNKNOWN_TYPE -1 -#define NDEF_TYPE1_TAG 1 -#define NDEF_TYPE2_TAG 2 -#define NDEF_TYPE3_TAG 3 -#define NDEF_TYPE4_TAG 4 -#define NDEF_MIFARE_CLASSIC_TAG 101 -#define NDEF_ICODE_SLI_TAG 102 - -/* Pre-defined tag type values. These must match the values in - * Ndef.java in the framework. - */ - -#define NDEF_MODE_READ_ONLY 1 -#define NDEF_MODE_READ_WRITE 2 -#define NDEF_MODE_UNKNOWN 3 - - -/* Name strings for target types. These *must* match the values in TagTechnology.java */ -#define TARGET_TYPE_UNKNOWN -1 -#define TARGET_TYPE_ISO14443_3A 1 -#define TARGET_TYPE_ISO14443_3B 2 -#define TARGET_TYPE_ISO14443_4 3 -#define TARGET_TYPE_FELICA 4 -#define TARGET_TYPE_ISO15693 5 -#define TARGET_TYPE_NDEF 6 -#define TARGET_TYPE_NDEF_FORMATABLE 7 -#define TARGET_TYPE_MIFARE_CLASSIC 8 -#define TARGET_TYPE_MIFARE_UL 9 - -#define SMX_SECURE_ELEMENT_ID 11259375 - -/* Maximum byte length of an AID. */ -#define AID_MAXLEN 16 - -/* Utility macros for logging */ -#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN - -#if 0 - #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); - #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#else - #define LOG_CALLBACK(...) - #define TRACE(...) -#endif - -struct nfc_jni_native_data -{ - /* Thread handle */ - pthread_t thread; - int running; - - /* Our VM */ - JavaVM *vm; - int env_version; - - /* Reference to the NFCManager instance */ - jobject manager; - - /* Cached objects */ - jobject cached_NfcTag; - jobject cached_P2pDevice; - - /* Target discovery configuration */ - int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - - /* Secure Element selected */ - int seId; - - /* LLCP params */ - int lto; - int miu; - int wks; - int opt; - - /* Tag detected */ - jobject tag; - - /* Lib Status */ - NFCSTATUS status; - - /* p2p modes */ - int p2p_initiator_modes; - int p2p_target_modes; - -}; - -typedef struct nfc_jni_native_monitor -{ - /* Mutex protecting native library against reentrance */ - pthread_mutex_t reentrance_mutex; - - /* Mutex protecting native library against concurrency */ - pthread_mutex_t concurrency_mutex; - - /* List used to track pending semaphores waiting for callback */ - struct listHead sem_list; - - /* List used to track incoming socket requests (and associated sync variables) */ - LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; - pthread_mutex_t incoming_socket_mutex; - pthread_cond_t incoming_socket_cond; - -} nfc_jni_native_monitor_t; - -typedef struct nfc_jni_callback_data -{ - /* Semaphore used to wait for callback */ - sem_t sem; - - /* Used to store the status sent by the callback */ - NFCSTATUS status; - - /* Used to provide a local context to the callback */ - void* pContext; - -} nfc_jni_callback_data_t; - -typedef struct nfc_jni_listen_data -{ - /* LLCP server socket receiving the connection request */ - phLibNfc_Handle pServerSocket; - - /* LLCP socket created from the connection request */ - phLibNfc_Handle pIncomingSocket; - - /* List entries */ - LIST_ENTRY(nfc_jni_listen_data) entries; - -} nfc_jni_listen_data_t; - -/* TODO: treat errors and add traces */ -#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) -#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) -#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) -#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) - -namespace android { - -extern JavaVM *vm; - -JNIEnv *nfc_get_env(); - -bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); -void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); -void nfc_cb_data_releaseAll(); - -const char* nfc_jni_get_status_name(NFCSTATUS status); -int nfc_jni_cache_object(JNIEnv *e, const char *clsname, - jobject *cached_obj); -struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); -struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); -nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); -nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); - -int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); -void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, - uint8_t count, jintArray* techList, jintArray* handleList, - jintArray* typeList); - -/* P2P */ -phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); -jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); - -/* TAG */ -jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); -jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); -phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); -jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); - -/* LLCP */ -phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e); -int register_com_android_nfc_NativeNfcTag(JNIEnv *e); -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); - -} // namespace android - -#endif diff --git a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp deleted file mode 100644 index 188edb4..0000000 --- a/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - pCallbackData->pContext = (void*)ssap; - TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_sendTo_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* -* Methods -*/ -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_SendTo()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SendTo(hRemoteDevice, - hLlcpSocket, - nsap, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) -{ - NFCSTATUS ret; - struct timespec ts; - uint8_t ssap; - jobject llcpPacket = NULL; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer; - jclass clsLlcpPacket; - jfieldID f; - jbyteArray receivedData = NULL; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create new LlcpPacket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) - { - ALOGE("Find LlcpPacket class error"); - goto clean_and_return; - } - - /* Get NativeConnectionless class object */ - clsLlcpPacket = e->GetObjectClass(llcpPacket); - if(e->ExceptionCheck()) - { - ALOGE("Get Object class error"); - goto clean_and_return; - } - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); - - sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); - sReceiveBuffer.length = linkMiu; - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - &cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ssap = (uint32_t)cb_data.pContext; - TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); - - /* Set Llcp Packet remote SAP */ - f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); - e->SetIntField(llcpPacket, f,(jbyte)ssap); - - /* Set Llcp Packet Buffer */ - ALOGD("Set LlcpPacket Data Buffer\n"); - f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); - receivedData = e->NewByteArray(sReceiveBuffer.length); - e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); - e->SetObjectField(llcpPacket, f, receivedData); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return llcpPacket; -} - -static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - TRACE("Close Connectionless socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, - - {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, - - {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", - gMethods, NELEM(gMethods)); -} - -} // android namespace diff --git a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/jni/com_android_nfc_NativeLlcpServiceSocket.cpp deleted file mode 100644 index 92de3e4..0000000 --- a/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode); -/* - * Callbacks - */ -static void nfc_jni_llcp_accept_socket_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -/* - * Utils - */ - -static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, - phLibNfc_Handle hServerSocket) -{ - nfc_jni_listen_data_t * pListenData; - phLibNfc_Handle pIncomingSocket = NULL; - - /* Look for a pending incoming connection on the current server */ - LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) - { - if (pListenData->pServerSocket == hServerSocket) - { - pIncomingSocket = pListenData->pIncomingSocket; - LIST_REMOVE(pListenData, entries); - free(pListenData); - break; - } - } - - return pIncomingSocket; -} - -/* - * Methods - */ -static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret = NFCSTATUS_SUCCESS; - struct timespec ts; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - jfieldID f; - jclass clsNativeLlcpSocket; - jobject clientSocket = NULL; - struct nfc_jni_callback_data cb_data; - phLibNfc_Handle hIncomingSocket, hServerSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Get server socket */ - hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Set socket options with the socket options of the service */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - - while(cb_data.status != NFCSTATUS_SUCCESS) - { - /* Wait for tag Notification */ - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { - pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); - } - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - /* Accept the incomming socket */ - TRACE("phLibNfc_Llcp_Accept()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Accept( hIncomingSocket, - &sOptions, - &sWorkingBuffer, - nfc_jni_llcp_transport_socket_err_callback, - nfc_jni_llcp_accept_socket_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - // NOTE: This may happen if link went down since incoming socket detected, then - // just drop it and start a new accept loop. - ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - continue; - } - TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ - ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); - } - } - - /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGD("LLCP Socket creation error"); - goto clean_and_return; - } - - /* Get NativeConnectionOriented class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGD("LLCP Socket get class object error"); - goto clean_and_return; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hIncomingSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - - TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return clientSocket; -} - -static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); - - TRACE("Close Service socket"); - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - /* TODO: implement accept abort */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); - - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("Close Service socket OK"); - return TRUE; - } - else - { - ALOGD("Close Service socket KO"); - return FALSE; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_NativeLlcpServiceSocket_doAccept}, - - {"doClose", "()Z", - (void *)com_NativeLlcpServiceSocket_doClose}, -}; - - -int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeLlcpSocket.cpp b/jni/com_android_nfc_NativeLlcpSocket.cpp deleted file mode 100644 index 0c0b830..0000000 --- a/jni/com_android_nfc_NativeLlcpSocket.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -namespace android { - -/* - * Callbacks - */ - -static void nfc_jni_disconnect_callback(void* pContext, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - -static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - TRACE("Socket connected\n"); - } - else - { - ALOGD("Socket not connected:"); - switch(nErrCode) - { - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: - { - ALOGD("> SAP NOT ACTIVE\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: - { - ALOGD("> SAP NOT FOUND\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: - { - ALOGD("> CONNECT REJECTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: - { - ALOGD("> CONNECT NOT ACCEPTED\n"); - }break; - - case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: - { - ALOGD("> SOCKET NOT AVAILABLE\n"); - }break; - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - - - - -static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcp_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Methods - */ -static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_Llcp_Connect(%d)",nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Connect(hRemoteDevice, - hLlcpSocket, - nSap, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("LLCP Connect request failed"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) -{ - NFCSTATUS ret; - struct timespec ts; - phNfc_sData_t serviceName = {0}; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Service socket */ - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - - TRACE("phLibNfc_Llcp_ConnectByUri()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, - hLlcpSocket, - &serviceName, - nfc_jni_connect_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - - /* Retrieve socket handle */ - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_Close()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return FALSE; - } - TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return TRUE; -} - -static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sSendBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jboolean result = JNI_FALSE; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); - sSendBuffer.length = (uint32_t)e->GetArrayLength(data); - - TRACE("phLibNfc_Llcp_Send()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Send(hRemoteDevice, - hLlcpSocket, - &sSendBuffer, - nfc_jni_send_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (sSendBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) -{ - NFCSTATUS ret; - struct timespec ts; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phNfc_sData_t sReceiveBuffer = {NULL, 0}; - struct nfc_jni_callback_data cb_data; - jint result = -1; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); - sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); - - TRACE("phLibNfc_Llcp_Recv()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Recv(hRemoteDevice, - hLlcpSocket, - &sReceiveBuffer, - nfc_jni_receive_callback, - (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_PENDING) - { - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - } - else if (ret == NFCSTATUS_SUCCESS) - { - result = sReceiveBuffer.length; - } - else - { - /* Return status should be either SUCCESS or PENDING */ - ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - -clean_and_return: - if (sReceiveBuffer.buffer != NULL) - { - e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.miu; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - -static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - phLibNfc_Handle hRemoteDevice; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; - - /* Retrieve handles */ - hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); - hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); - - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, - hLlcpSocket, - &remoteSocketOption); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return remoteSocketOption.rw; - } - else - { - ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return 0; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnect}, - - {"doConnectBy", "(Ljava/lang/String;)Z", - (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, - - {"doClose", "()Z", - (void *)com_android_nfc_NativeLlcpSocket_doClose}, - - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeLlcpSocket_doSend}, - - {"doReceive", "([B)I", - (void *)com_android_nfc_NativeLlcpSocket_doReceive}, - - {"doGetRemoteSocketMiu", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, - - {"doGetRemoteSocketRw", "()I", - (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, -}; - - -int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp deleted file mode 100644 index 704ee6a..0000000 --- a/jni/com_android_nfc_NativeNfcManager.cpp +++ /dev/null @@ -1,2622 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "com_android_nfc.h" - -#define ERROR_BUFFER_TOO_SMALL -12 -#define ERROR_INSUFFICIENT_RESOURCES -9 - -extern uint32_t libnfc_llc_error_count; - -static phLibNfc_sConfig_t gDrvCfg; -void *gHWRef; -static phNfc_sData_t gInputParam; -static phNfc_sData_t gOutputParam; - -uint8_t device_connected_flag; -static bool driverConfigured = FALSE; - -static phLibNfc_Handle hLlcpHandle; -static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; -static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; - -static jmethodID cached_NfcManager_notifyNdefMessageListeners; -static jmethodID cached_NfcManager_notifyTransactionListeners; -static jmethodID cached_NfcManager_notifyLlcpLinkActivation; -static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; -static jmethodID cached_NfcManager_notifyTargetDeselected; - -static jmethodID cached_NfcManager_notifySeFieldActivated; -static jmethodID cached_NfcManager_notifySeFieldDeactivated; - -static jmethodID cached_NfcManager_notifySeApduReceived; -static jmethodID cached_NfcManager_notifySeMifareAccess; -static jmethodID cached_NfcManager_notifySeEmvCardRemoval; - -namespace android { - -phLibNfc_Handle storedHandle = 0; - -struct nfc_jni_native_data *exported_nat = NULL; - -/* Internal functions declaration */ -static void *nfc_jni_client_thread(void *arg); -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_se_set_mode_callback(void *context, - phLibNfc_Handle handle, NFCSTATUS status); -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status); -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); -static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); - -/* - * Deferred callback called when client thread must be exited - */ -static void client_kill_deferred_call(void* arg) -{ - struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; - - nat->running = FALSE; -} - -static void kill_client(nfc_jni_native_data *nat) -{ - phDal4Nfc_Message_Wrapper_t wrapper; - phLibNfc_DeferredCall_t *pMsg; - - usleep(50000); - - ALOGD("Terminating client thread..."); - - pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); - pMsg->pCallback = client_kill_deferred_call; - pMsg->pParameter = (void*)nat; - - wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; - wrapper.msg.pMsgData = pMsg; - wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); - - phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); -} - -static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_ioctl_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_deinit_download_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) -{ - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - struct timespec ts; - NFCSTATUS status = NFCSTATUS_FAILED; - phLibNfc_StackCapabilities_t caps; - struct nfc_jni_callback_data cb_data; - bool result; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - if(update) - { - //deinit - TRACE("phLibNfc_Mgt_DeInitialize() (download)"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts)) - { - ALOGW("Deinitialization timed out (download)"); - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGW("Deinitialization FAILED (download)"); - } - TRACE("Deinitialization SUCCESS (download)"); - } - - result = performDownload(nat, false); - - if (!result) { - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - status = cb_data.status; - goto clean_and_return; - } - - /* ====== CAPABILITIES ======= */ - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /*Download is successful*/ - status = NFCSTATUS_SUCCESS; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - return status; -} - -static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) -{ - char value[PROPERTY_VALUE_MAX]; - int result = FALSE; - NFCSTATUS status; - - /* ====== CONFIGURE DRIVER ======= */ - /* Configure hardware link */ - gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); - - TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); - REENTRANCE_UNLOCK(); - if(status == NFCSTATUS_ALREADY_INITIALISED) { - ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) - { - ALOGE("pthread_create failed"); - goto clean_and_return; - } - - driverConfigured = TRUE; - -clean_and_return: - return result; -} - -static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) -{ - int result = FALSE; - NFCSTATUS status; - - /* Unconfigure driver */ - TRACE("phLibNfc_Mgt_UnConfigureDriver()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); - } - else - { - ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = TRUE; - } - - driverConfigured = FALSE; - - return result; -} - -/* Initialization function */ -static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { - struct timespec ts; - uint8_t resp[16]; - NFCSTATUS status; - phLibNfc_StackCapabilities_t caps; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; - phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; - struct nfc_jni_callback_data cb_data; - uint8_t firmware_status; - uint8_t update = TRUE; - int result = JNI_FALSE; - const hw_module_t* hw_module; - nfc_pn544_device_t* pn544_dev = NULL; - int ret = 0; - ALOGD("Start Initialization\n"); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Get EEPROM values and device port from product-specific settings */ - ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); - if (ret) { - ALOGE("hw_get_module() failed."); - goto clean_and_return; - } - ret = nfc_pn544_open(hw_module, &pn544_dev); - if (ret) { - ALOGE("Could not open pn544 hw_module."); - goto clean_and_return; - } - if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { - ALOGE("Could not load EEPROM settings"); - goto clean_and_return; - } - - /* Reset device connected handle */ - device_connected_flag = 0; - - /* Reset stored handle */ - storedHandle = 0; - - /* Initialize Driver */ - if(!driverConfigured) - { - nfc_jni_configure_driver(nat); - } - - /* ====== INITIALIZE ======= */ - - TRACE("phLibNfc_Mgt_Initialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - update = FALSE; - goto force_download; - } - TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - update = FALSE; - goto force_download; - } - - /* ====== CAPABILITIES ======= */ - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - } - else - { - ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", - caps.psDevCapabilities.hal_version, - caps.psDevCapabilities.fw_version, - caps.psDevCapabilities.hw_version, - caps.psDevCapabilities.model_id, - caps.psDevCapabilities.hci_version, - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], - caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], - caps.psDevCapabilities.firmware_update_info); - } - - /* ====== FIRMWARE VERSION ======= */ - if(caps.psDevCapabilities.firmware_update_info) - { -force_download: - for (i=0; i<3; i++) - { - TRACE("Firmware version not UpToDate"); - status = nfc_jni_download_locked(nat, update); - if(status == NFCSTATUS_SUCCESS) - { - ALOGI("Firmware update SUCCESS"); - break; - } - ALOGW("Firmware update FAILED"); - update = FALSE; - } - if(i>=3) - { - ALOGE("Unable to update firmware, giving up"); - goto clean_and_return; - } - } - else - { - TRACE("Firmware version UpToDate"); - } - /* ====== EEPROM SETTINGS ======= */ - - // Update EEPROM settings - TRACE("****** START EEPROM SETTINGS UPDATE ******"); - for (i = 0; i < pn544_dev->num_eeprom_settings; i++) - { - char eeprom_property[PROPERTY_KEY_MAX]; - char eeprom_value[PROPERTY_VALUE_MAX]; - uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); - TRACE("> EEPROM SETTING: %d", i); - - // Check for override of this EEPROM value in properties - snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", - eeprom_base[1], eeprom_base[2]); - TRACE(">> Checking property: %s", eeprom_property); - if (property_get(eeprom_property, eeprom_value, "") == 2) { - int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); - ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", - eeprom_base[1], eeprom_base[2], eeprom_value_num); - eeprom_base[3] = eeprom_value_num; - } - - TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], - eeprom_base[3]); - gInputParam.buffer = eeprom_base; - gInputParam.length = 0x04; - gOutputParam.buffer = resp; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Initialization Status */ - if (cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - } - TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); - - /* ====== SECURE ELEMENTS ======= */ - - REENTRANCE_LOCK(); - ALOGD("phLibNfc_SE_GetSecureElementList()"); - status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - - ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i < No_SE; i++) - { - if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); - } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); - } - - /* Set SE mode - Off */ - REENTRANCE_LOCK(); - status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, - phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - } - - /* ====== LLCP ======= */ - - /* LLCP Params */ - TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); - LlcpConfigInfo.miu = nat->miu; - LlcpConfigInfo.lto = nat->lto; - LlcpConfigInfo.wks = nat->wks; - LlcpConfigInfo.option = nat->opt; - - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, - nfc_jni_llcpcfg_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, - nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* ===== DISCOVERY ==== */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.Duration = 300000; /* in ms */ - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Register for the card emulation mode */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); - - - /* ====== END ======= */ - - ALOGI("NFC Initialized"); - - result = TRUE; - -clean_and_return: - if (result != TRUE) - { - if(nat) - { - kill_client(nat); - } - } - if (pn544_dev != NULL) { - nfc_pn544_close(pn544_dev); - } - nfc_cb_data_deinit(&cb_data); - - return result; -} - -static int is_user_build() { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.build.type", value, ""); - return !strncmp("user", value, PROPERTY_VALUE_MAX); -} - -/* - * Last-chance fallback when there is no clean way to recover - * Performs a software reset - */ -void emergency_recovery(struct nfc_jni_native_data *nat) { - if (!is_user_build()) { - ALOGE("emergency_recovery: force restart of NFC service"); - } else { - // dont recover immediately, so we can debug - unsigned int t; - for (t=1; t < 1000000; t <<= 1) { - ALOGE("emergency_recovery: NFC stack dead-locked"); - sleep(t); - } - } - phLibNfc_Mgt_Recovery(); - abort(); // force a noisy crash -} - -void nfc_jni_reset_timeout_values() -{ - REENTRANCE_LOCK(); - phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); - phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); - phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); - phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); - REENTRANCE_UNLOCK(); -} - -/* - * Restart the polling loop when unable to perform disconnect - */ -void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) -{ - nfc_jni_start_discovery_locked(nat, true); -} - - /* - * Utility to recover UID from target infos - */ -static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - phNfc_sData_t uid; - - switch(psRemoteDevInfo->RemDevType) - { - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_3A_PICC: - case phNfc_eMifare_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; - break; - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; - uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); - break; - case phNfc_eFelica_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; - uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; - break; - case phNfc_eJewel_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; - break; - case phNfc_eISO15693_PICC: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; - uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; - break; - case phNfc_eNfcIP1_Target: - case phNfc_eNfcIP1_Initiator: - uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; - uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; - break; - default: - uid.buffer = NULL; - uid.length = 0; - break; - } - - return uid; -} - -/* - * NFC stack message processing - */ -static void *nfc_jni_client_thread(void *arg) -{ - struct nfc_jni_native_data *nat; - JNIEnv *e; - JavaVMAttachArgs thread_args; - phDal4Nfc_Message_Wrapper_t wrapper; - - nat = (struct nfc_jni_native_data *)arg; - - thread_args.name = "NFC Message Loop"; - thread_args.version = nat->env_version; - thread_args.group = NULL; - - nat->vm->AttachCurrentThread(&e, &thread_args); - pthread_setname_np(pthread_self(), "message"); - - TRACE("NFC client started"); - nat->running = TRUE; - while(nat->running == TRUE) - { - /* Fetch next message from the NFC stack message queue */ - if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, - sizeof(phLibNfc_Message_t), 0, 0) == -1) - { - ALOGE("NFC client received bad message"); - continue; - } - - switch(wrapper.msg.eMsgType) - { - case PH_LIBNFC_DEFERREDCALL_MSG: - { - phLibNfc_DeferredCall_t *msg = - (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); - - REENTRANCE_LOCK(); - msg->pCallback(msg->pParameter); - REENTRANCE_UNLOCK(); - - break; - } - } - } - TRACE("NFC client stopped"); - - nat->vm->DetachCurrentThread(); - - return NULL; -} - -extern uint8_t nfc_jni_is_ndef; -extern uint8_t *nfc_jni_ndef_buf; -extern uint32_t nfc_jni_ndef_buf_len; - -static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = -{ - 3, - { 0x46, 0x66, 0x6D } -}; - -/* - * Callbacks - */ - -/* P2P - LLCP callbacks */ -static void nfc_jni_llcp_linkStatus_callback(void *pContext, - phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) -{ - phFriNfc_Llcp_sLinkParameters_t sLinkParams; - JNIEnv *e; - NFCSTATUS status; - - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; - - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - /* Update link status */ - g_eLinkStatus = eLinkStatus; - - if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) - { - REENTRANCE_LOCK(); - status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_SUCCESS) - { - ALOGW("GetRemote Info failded - Status = %02x",status); - } - else - { - ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, - sLinkParams.miu, - sLinkParams.option, - sLinkParams.wks); - device_connected_flag = 1; - } - } - else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) - { - ALOGI("LLCP Link deactivated"); - free(pContextData); - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Reset incoming socket list */ - while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) - { - pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); - LIST_REMOVE(pListenData, entries); - free(pListenData); - } - - /* Notify manager that the LLCP is lost or deactivated */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } -} - -static void nfc_jni_checkLlcp_callback(void *context, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; - - LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, - phLibNfc_Handle hIncomingSocket) -{ - phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; - nfc_jni_listen_data_t * pListenData = NULL; - nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); - - TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); - - pthread_mutex_lock(&pMonitor->incoming_socket_mutex); - - /* Store the connection request */ - pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); - if (pListenData == NULL) - { - ALOGE("Failed to create structure to handle incoming LLCP connection request"); - goto clean_and_return; - } - pListenData->pServerSocket = hServiceSocket; - pListenData->pIncomingSocket = hIncomingSocket; - LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); - - /* Signal pending accept operations that the list is updated */ - pthread_cond_broadcast(&pMonitor->incoming_socket_cond); - -clean_and_return: - pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); -} - -void nfc_jni_llcp_transport_socket_err_callback(void* pContext, - uint8_t nErrCode) -{ - PHNFC_UNUSED_VARIABLE(pContext); - - TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); - - if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) - { - ALOGW("Frame Rejected - Disconnected"); - } - else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) - { - ALOGD("Socket Disconnected"); - } -} - - -static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_discover_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNoOfRemoteDev) -{ - // Always prefer p2p targets over other targets. Otherwise, select the first target - // reported. - uint8_t preferred_index = 0; - for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { - if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { - preferred_index = i; - } - } - return preferred_index; -} - -static void nfc_jni_Discovery_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, NFCSTATUS status) -{ - JNIEnv *e; - NFCSTATUS ret; - jclass tag_cls = NULL; - jobject target_array; - jobject tag; - jmethodID ctor; - jfieldID f; - const char * typeName; - jbyteArray tagUid; - jbyteArray generalBytes = NULL; - struct nfc_jni_native_data *nat; - struct timespec ts; - phNfc_sData_t data; - int i; - int target_index = 0; // Target that will be reported (if multiple can be >0) - - nat = (struct nfc_jni_native_data *)pContext; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); - - /* Notify manager that a target was deselected */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); - TRACE("Discovered %d tags", uNofRemoteDev); - - target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); - - /* Reset device connected flag */ - device_connected_flag = 1; - phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; - phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - - tag_cls = e->GetObjectClass(nat->cached_P2pDevice); - if(e->ExceptionCheck()) - { - ALOGE("Get Object Class Error"); - kill_client(nat); - return; - } - - /* New target instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - /* Set P2P Target mode */ - f = e->GetFieldID(tag_cls, "mMode", "I"); - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - ALOGD("Discovered P2P Initiator"); - e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); - } - else - { - ALOGD("Discovered P2P Target"); - e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); - } - - if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - { - /* Set General Bytes */ - f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes length ="); - for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) - { - ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); - } - - generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - - e->SetByteArrayRegion(generalBytes, 0, - remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, - (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); - - e->SetObjectField(tag, f, generalBytes); - } - - /* Set tag handle */ - f = e->GetFieldID(tag_cls, "mHandle", "I"); - e->SetIntField(tag, f,(jint)remDevHandle); - TRACE("Target handle = 0x%08x",remDevHandle); - } - else - { - tag_cls = e->GetObjectClass(nat->cached_NfcTag); - if(e->ExceptionCheck()) - { - kill_client(nat); - return; - } - - /* New tag instance */ - ctor = e->GetMethodID(tag_cls, "", "()V"); - tag = e->NewObject(tag_cls, ctor); - - bool multi_protocol = false; - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - TRACE("Multiple Protocol TAG detected\n"); - multi_protocol = true; - } - - /* Set tag UID */ - f = e->GetFieldID(tag_cls, "mUid", "[B"); - data = get_target_uid(remDevInfo); - tagUid = e->NewByteArray(data.length); - if(data.length > 0) - { - e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); - } - e->SetObjectField(tag, f, tagUid); - - /* Generate technology list */ - jintArray techList; - jintArray handleList; - jintArray typeList; - nfc_jni_get_technology_tree(e, psRemoteDevList, - multi_protocol ? uNofRemoteDev : 1, - &techList, &handleList, &typeList); - - /* Push the technology list into the java object */ - f = e->GetFieldID(tag_cls, "mTechList", "[I"); - e->SetObjectField(tag, f, techList); - - f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); - e->SetObjectField(tag, f, handleList); - - f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); - e->SetObjectField(tag, f, typeList); - - f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); - e->SetIntField(tag, f,(jint)-1); - - f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); - e->SetIntField(tag, f,(jint)-1); - } - - storedHandle = remDevHandle; - if (nat->tag != NULL) { - e->DeleteGlobalRef(nat->tag); - } - nat->tag = e->NewGlobalRef(tag); - - /* Notify the service */ - TRACE("Notify Nfc Service"); - if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) - || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) - { - /* Store the hanlde of the P2P device */ - hLlcpHandle = remDevHandle; - - /* Notify manager that new a P2P device was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - else - { - /* Notify manager that new a tag was found */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); - if(e->ExceptionCheck()) - { - ALOGE("Exception occured"); - kill_client(nat); - } - } - e->DeleteLocalRef(tag); - } -} - -static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_init_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_deinit_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Card Emulation callback */ -static void nfc_jni_transaction_callback(void *context, - phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, - phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) -{ - JNIEnv *e; - jobject tmp_array = NULL; - jobject mifare_block = NULL; - struct nfc_jni_native_data *nat; - phNfc_sData_t *aid; - phNfc_sData_t *mifare_command; - struct nfc_jni_callback_data *pCallbackData; - int i=0; - - LOG_CALLBACK("nfc_jni_transaction_callback", status); - - nat = (struct nfc_jni_native_data *)context; - - nat->vm->GetEnv( (void **)&e, nat->env_version); - - if(status == NFCSTATUS_SUCCESS) - { - switch(evt_type) - { - case phLibNfc_eSE_EvtStartTransaction: - { - TRACE("> SE EVT_START_TRANSACTION"); - if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) - { - aid = &(evt_info->UiccEvtInfo.aid); - - ALOGD("> AID DETECTED"); - - if(aid != NULL) - { - char aid_str[AID_MAXLEN * 2 + 1]; - aid_str[0] = '\0'; - for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { - snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); - } - ALOGD("> AID: %s", aid_str); - - tmp_array = e->NewByteArray(aid->length); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - goto error; - } - - TRACE("Notify Nfc Service"); - /* Notify manager that a new event occurred on a SE */ - e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); - if(e->ExceptionCheck()) - { - goto error; - } - } - else - { - ALOGD("> NO AID DETECTED"); - } - }break; - - case phLibNfc_eSE_EvtApduReceived: - { - phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); - TRACE("> SE EVT_APDU_RECEIVED"); - - if (apdu != NULL) { - TRACE(" APDU length=%d", apdu->length); - tmp_array = e->NewByteArray(apdu->length); - if (tmp_array == NULL) { - goto error; - } - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); - if (e->ExceptionCheck()) { - goto error; - } - } else { - TRACE(" APDU EMPTY"); - } - - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); - }break; - - case phLibNfc_eSE_EvtCardRemoval: - { - TRACE("> SE EVT_EMV_CARD_REMOVAL"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); - }break; - - case phLibNfc_eSE_EvtMifareAccess: - { - TRACE("> SE EVT_MIFARE_ACCESS"); - mifare_command = &(evt_info->UiccEvtInfo.aid); - TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); - tmp_array = e->NewByteArray(2); - if (tmp_array == NULL) - { - goto error; - } - - e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); - if(e->ExceptionCheck()) - { - goto error; - } - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); - }break; - - case phLibNfc_eSE_EvtFieldOn: - { - TRACE("> SE EVT_FIELD_ON"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); - }break; - - case phLibNfc_eSE_EvtFieldOff: - { - TRACE("> SE EVT_FIELD_OFF"); - TRACE("Notify Nfc Service"); - e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); - }break; - - default: - { - TRACE("Unknown SE event"); - }break; - } - } - else - { - ALOGE("SE transaction notification error"); - goto error; - } - - /* Function finished, now clean and return */ - goto clean_and_return; - - error: - /* In case of error, just discard the notification */ - ALOGE("Failed to send SE transaction notification"); - e->ExceptionClear(); - - clean_and_return: - if(tmp_array != NULL) - { - e->DeleteLocalRef(tmp_array); - } -} - -static void nfc_jni_se_set_mode_callback(void *pContext, - phLibNfc_Handle handle, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* - * NFCManager methods - */ - -static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) -{ - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ - nfc_jni_reset_timeout_values(); - - /* Reload the p2p modes */ - nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator - nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target - nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; - - /* Reset device connected flag */ - device_connected_flag = 0; - - /* Start Polling loop */ - TRACE("****** Start NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, - nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - -static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) -{ - phLibNfc_sADD_Cfg_t discovery_cfg; - NFCSTATUS ret; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - discovery_cfg.PollDevInfo.PollEnabled = 0; - discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; - discovery_cfg.NfcIP_Target_Mode = 0; - discovery_cfg.NfcIP_Tgt_Disable = TRUE; - - /* Start Polling loop */ - TRACE("****** Stop NFC Discovery ******"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", - discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", - discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", - discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); - - if(ret != NFCSTATUS_PENDING) - { - emergency_recovery(nat); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); -} - - -static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nfc_jni_stop_discovery_locked(nat); - - CONCURRENCY_UNLOCK(); - -} - -static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - - CONCURRENCY_LOCK(); - - nat = nfc_jni_get_nat(e, o); - - /* Register callback for remote device notifications. - * Must re-register every time we turn on discovery, since other operations - * (such as opening the Secure Element) can change the remote device - * notification callback*/ - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", - nat->registry_info.Jewel==TRUE?"J":"", - nat->registry_info.MifareUL==TRUE?"UL":"", - nat->registry_info.MifareStd==TRUE?"Mi":"", - nat->registry_info.Felica==TRUE?"F":"", - nat->registry_info.ISO14443_4A==TRUE?"4A":"", - nat->registry_info.ISO14443_4B==TRUE?"4B":"", - nat->registry_info.NFC==TRUE?"P2P":"", - nat->registry_info.ISO15693==TRUE?"R":"", ret); - - nfc_jni_start_discovery_locked(nat, false); -clean_and_return: - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { - CONCURRENCY_LOCK(); - nfc_jni_reset_timeout_values(); - CONCURRENCY_UNLOCK(); -} - -static void setFelicaTimeout(jint timeout) { - // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. - // It can be set to 0 to disable the timeout altogether, in which case we - // use the sw watchdog as a fallback. - if (timeout <= 255) { - phLibNfc_SetFelicaTimeout(timeout); - } else { - // Disable hw timeout, use sw watchdog for timeout - phLibNfc_SetFelicaTimeout(0); - phLibNfc_SetHciTimeout(timeout); - } - -} -// Calculates ceiling log2 of value -static unsigned int log2(int value) { - unsigned int ret = 0; - bool isPowerOf2 = ((value & (value - 1)) == 0); - while ( (value >> ret) > 1 ) ret++; - if (!isPowerOf2) ret++; - return ret; -} - -// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X -// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X -// -// We keep the constant part of the formula in a static; note the factor -// 1000 off, which is due to the fact that the formula calculates seconds, -// but this method gets milliseconds as an argument. -static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; - -static int calcTimeout(int timeout_in_ms) { - // timeout = (256 * 16 / 13560000) * 2 ^ X - // First find the first X for which timeout > requested timeout - return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); -} - -static void setIsoDepTimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - // Then re-compute the actual timeout based on X - double actual_timeout = nxp_nfc_timeout_factor * (1 << value); - // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, - // but it will take some time to get back through the sw layers. - // 500 ms should be enough). - phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); - value |= 0x10; // bit 4 to enable timeout - phLibNfc_SetIsoXchgTimeout(value); - } - else { - // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout - // must be disabled completely, to prevent the PN544 from aborting - // the transaction. We reuse the HCI sw watchdog to catch the timeout - // in that case. - phLibNfc_SetIsoXchgTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static void setNfcATimeout(jint timeout) { - if (timeout <= 4900) { - int value = calcTimeout(timeout); - phLibNfc_SetMifareRawTimeout(value); - } - else { - // Disable mifare raw timeout, use HCI sw watchdog instead - phLibNfc_SetMifareRawTimeout(0x00); - phLibNfc_SetHciTimeout(timeout); - } -} - -static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, - jint tech, jint timeout) { - bool success = false; - CONCURRENCY_LOCK(); - if (timeout <= 0) { - ALOGE("Timeout must be positive."); - return false; - } else { - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - setNfcATimeout(timeout); - success = true; - break; - case TARGET_TYPE_ISO14443_4: - setIsoDepTimeout(timeout); - success = true; - break; - case TARGET_TYPE_FELICA: - setFelicaTimeout(timeout); - success = true; - break; - default: - ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); - success = false; - } - } - CONCURRENCY_UNLOCK(); - return success; -} - -static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, - jint tech) { - int timeout = -1; - CONCURRENCY_LOCK(); - switch (tech) { - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - // Intentional fall-through, Mifare UL, Classic - // transceive just uses raw 3A frames - case TARGET_TYPE_ISO14443_3A: - timeout = phLibNfc_GetMifareRawTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_ISO14443_4: - timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Timeout returned from libnfc needs conversion to ms - timeout = (nxp_nfc_timeout_factor * (1 << timeout)); - } - break; - case TARGET_TYPE_FELICA: - timeout = phLibNfc_GetFelicaTimeout(); - if (timeout == 0) { - timeout = phLibNfc_GetHciTimeout(); - } else { - // Felica timeout already in ms - } - break; - default: - ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); - break; - } - CONCURRENCY_UNLOCK(); - return timeout; -} - - -static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct nfc_jni_native_data *nat = NULL; - jclass cls; - jobject obj; - jfieldID f; - - TRACE("****** Init Native Structure ******"); - - /* Initialize native structure */ - nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); - if(nat == NULL) - { - ALOGD("malloc of nfc_jni_native_data failed"); - return FALSE; - } - memset(nat, 0, sizeof(*nat)); - e->GetJavaVM(&(nat->vm)); - nat->env_version = e->GetVersion(); - nat->manager = e->NewGlobalRef(o); - - cls = e->GetObjectClass(o); - f = e->GetFieldID(cls, "mNative", "I"); - e->SetIntField(o, f, (jint)nat); - - /* Initialize native cached references */ - cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); - - cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, - "notifyTransactionListeners", "([B)V"); - - cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); - - cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, - "notifyTargetDeselected","()V"); - - cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, - "notifySeFieldActivated", "()V"); - - cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, - "notifySeFieldDeactivated", "()V"); - - cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, - "notifySeApduReceived", "([B)V"); - - cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, - "notifySeMifareAccess", "([B)V"); - - cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, - "notifySeEmvCardRemoval", "()V"); - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) - { - ALOGD("Native Structure initialization failed"); - return FALSE; - } - TRACE("****** Init Native Structure OK ******"); - return TRUE; - -} - -/* Init/Deinit method */ -static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - int init_result = JNI_FALSE; -#ifdef TNFC_EMULATOR_ONLY - char value[PROPERTY_VALUE_MAX]; -#endif - jboolean result; - - CONCURRENCY_LOCK(); - -#ifdef TNFC_EMULATOR_ONLY - if (!property_get("ro.kernel.qemu", value, 0)) - { - ALOGE("NFC Initialization failed: not running in an emulator\n"); - goto clean_and_return; - } -#endif - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - nat->seId = SMX_SECURE_ELEMENT_ID; - - nat->lto = 150; // LLCP_LTO - nat->miu = 128; // LLCP_MIU - // WKS indicates well-known services; 1 << sap for each supported SAP. - // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) - nat->wks = 0x13; // LLCP_WKS - nat->opt = 0; // LLCP_OPT - nat->p2p_initiator_modes = phNfc_eP2P_ALL; - nat->p2p_target_modes = 0x0E; // All passive except 106, active - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; - nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; - - nat->registry_info.MifareUL = TRUE; - nat->registry_info.MifareStd = TRUE; - nat->registry_info.ISO14443_4A = TRUE; - nat->registry_info.ISO14443_4B = TRUE; - nat->registry_info.Jewel = TRUE; - nat->registry_info.Felica = TRUE; - nat->registry_info.NFC = TRUE; - nat->registry_info.ISO15693 = TRUE; - - exported_nat = nat; - - /* Perform the initialization */ - init_result = nfc_jni_initialize(nat); - -clean_and_return: - CONCURRENCY_UNLOCK(); - - /* Convert the result and return */ - return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; -} - -static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) -{ - struct timespec ts; - NFCSTATUS status; - int result = JNI_FALSE; - struct nfc_jni_native_data *nat; - int bStackReset = FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Clear previous configuration */ - memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); - memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); - - /* Create the local semaphore */ - if (nfc_cb_data_init(&cb_data, NULL)) - { - TRACE("phLibNfc_Mgt_DeInitialize()"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (status == NFCSTATUS_PENDING) - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += 5; - - /* Wait for callback response */ - if(sem_timedwait(&cb_data.sem, &ts) == -1) - { - ALOGW("Operation timed out"); - bStackReset = TRUE; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Failed to deinit the stack"); - bStackReset = TRUE; - } - } - else - { - TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - bStackReset = TRUE; - } - nfc_cb_data_deinit(&cb_data); - } - else - { - ALOGE("Failed to create semaphore (errno=0x%08x)", errno); - bStackReset = TRUE; - } - - kill_client(nat); - - if(bStackReset == TRUE) - { - /* Complete deinit. failed, try hard restart of NFC */ - ALOGW("Reseting stack..."); - emergency_recovery(nat); - } - - result = nfc_jni_unconfigure_driver(nat); - - TRACE("NFC Deinitialized"); - - CONCURRENCY_UNLOCK(); - - return TRUE; -} - -/* Secure Element methods */ -static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { - NFCSTATUS ret; - jintArray list= NULL; - phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; - - TRACE("****** Get Secure Element List ******"); - - TRACE("phLibNfc_SE_GetSecureElementList()"); - REENTRANCE_LOCK(); - ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_SUCCESS) { - ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - return list; - } - TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, - nfc_jni_get_status_name(ret)); - - TRACE("Nb SE: %d", se_count); - list =e->NewIntArray(se_count); - for (i = 0; i < se_count; i++) { - if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { - ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { - ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); - ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); - } - e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); - } - - e->DeleteLocalRef(list); - - return list; -} - -static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Select Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Virtual */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING) { - ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { - NFCSTATUS ret; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) { - goto clean_and_return; - } - - TRACE("****** Deselect Secure Element ******"); - - TRACE("phLibNfc_SE_SetMode()"); - /* Set SE mode - Default */ - REENTRANCE_LOCK(); - ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, - nfc_jni_se_set_mode_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); - if (ret != NFCSTATUS_PENDING) { - ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if (sem_wait(&cb_data.sem)) { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); -} - -/* Llcp methods */ - -static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - bool freeData = false; - jboolean result = JNI_FALSE; - struct nfc_jni_native_data *nat; - struct nfc_jni_callback_data *cb_data; - - - CONCURRENCY_LOCK(); - - /* Memory allocation for cb_data - * This is on the heap because it is used by libnfc - * even after this call has succesfully finished. It is only freed - * upon link closure in nfc_jni_llcp_linkStatus_callback. - */ - cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(cb_data, (void*)nat)) - { - goto clean_and_return; - } - - /* Check LLCP compliancy */ - TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, - nfc_jni_checkLlcp_callback, - nfc_jni_llcp_linkStatus_callback, - (void*)cb_data); - REENTRANCE_UNLOCK(); - /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol - * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ - if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - freeData = true; - goto clean_and_return; - } - TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data->sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data->status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(cb_data); - if (freeData) { - free(cb_data); - } - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Activate(hLlcpHandle); - REENTRANCE_UNLOCK(); - if(ret == NFCSTATUS_SUCCESS) - { - TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_TRUE; - } - else - { - ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - return JNI_FALSE; - } -} - - - -static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, - jint nSap, jstring sn) -{ - NFCSTATUS ret; - jobject connectionlessSocket = NULL; - phLibNfc_Handle hLlcpSocket; - struct nfc_jni_native_data *nat; - phNfc_sData_t sWorkingBuffer = {NULL, 0}; - phNfc_sData_t serviceName = {NULL, 0}; - phLibNfc_Llcp_sLinkParameters_t sParams; - jclass clsNativeConnectionlessSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Allocate Working buffer length */ - phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); - sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, - NULL, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - - /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) - { - goto error; - } - - /* Get NativeConnectionless class object */ - clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); - if(e->ExceptionCheck()) - { - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); - e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); - TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); - - /* Set the miu link of the connectionless socket */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); - e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); - TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); - e->SetIntField(connectionlessSocket, f,(jint)nSap); - TRACE("Connectionless socket SAP = %d\n",nSap); - - return connectionlessSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - - if (sWorkingBuffer.buffer != NULL) { - free(sWorkingBuffer.buffer); - } - - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) -{ - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - phNfc_sData_t serviceName; - struct nfc_jni_native_data *nat; - jobject serviceSocket = NULL; - jclass clsNativeLlcpServiceSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - goto error; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Service socket */ - if (sn == NULL) { - serviceName.buffer = NULL; - serviceName.length = 0; - } else { - serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); - serviceName.length = (uint32_t)e->GetStringUTFLength(sn); - } - - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - ret = phLibNfc_Llcp_Close(hLlcpSocket); - goto error; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Listen( hLlcpSocket, - nfc_jni_llcp_transport_listen_socket_callback, - (void*)hLlcpSocket); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - /* Close created socket */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - goto error; - } - TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) - { - ALOGE("Llcp Socket object creation error"); - goto error; - } - - /* Get NativeLlcpServiceSocket class object */ - clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); - if(e->ExceptionCheck()) - { - ALOGE("Llcp Socket get object class error"); - goto error; - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); - e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); - TRACE("Service socket Handle = %02x\n",hLlcpSocket); - - /* Set socket linear buffer length */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); - e->SetIntField(serviceSocket, f,(jint)linearBufferLength); - TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); - e->SetIntField(serviceSocket, f,(jint)miu); - TRACE("Service socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); - e->SetIntField(serviceSocket, f,(jint)rw); - TRACE("Service socket RW = %d\n",rw); - - return serviceSocket; -error: - if (serviceName.buffer != NULL) { - e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); - } - return NULL; -} - -static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) -{ - jobject clientSocket = NULL; - NFCSTATUS ret; - phLibNfc_Handle hLlcpSocket; - phLibNfc_Llcp_sSocketOptions_t sOptions; - phNfc_sData_t sWorkingBuffer; - struct nfc_jni_native_data *nat; - jclass clsNativeLlcpSocket; - jfieldID f; - - /* Retrieve native structure address */ - nat = nfc_jni_get_nat(e, o); - - /* Set Connection Oriented socket options */ - sOptions.miu = miu; - sOptions.rw = rw; - - /* Allocate Working buffer length */ - sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; - sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); - - /* Create socket */ - TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, - &sOptions, - &sWorkingBuffer, - &hLlcpSocket, - nfc_jni_llcp_transport_socket_err_callback, - (void*)nat); - REENTRANCE_UNLOCK(); - - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - lastErrorStatus = ret; - return NULL; - } - TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) - { - ALOGE("Llcp socket object creation error"); - return NULL; - } - - /* Get NativeConnectionless class object */ - clsNativeLlcpSocket = e->GetObjectClass(clientSocket); - if(e->ExceptionCheck()) - { - ALOGE("Get class object error"); - return NULL; - } - - /* Test if an SAP number is present */ - if(nSap != 0) - { - /* Bind socket */ - TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - lastErrorStatus = ret; - ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - /* Close socket created */ - REENTRANCE_LOCK(); - ret = phLibNfc_Llcp_Close(hLlcpSocket); - REENTRANCE_UNLOCK(); - return NULL; - } - TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Set socket SAP */ - f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); - e->SetIntField(clientSocket, f,(jint)nSap); - TRACE("socket SAP = %d\n",nSap); - } - - /* Set socket handle */ - f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); - e->SetIntField(clientSocket, f,(jint)hLlcpSocket); - TRACE("socket Handle = %02x\n",hLlcpSocket); - - /* Set socket MIU */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); - e->SetIntField(clientSocket, f,(jint)miu); - TRACE("socket MIU = %d\n",miu); - - /* Set socket RW */ - f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); - e->SetIntField(clientSocket, f,(jint)rw); - TRACE("socket RW = %d\n",rw); - - - return clientSocket; -} - -static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) -{ - TRACE("Last Error Status = 0x%02x",lastErrorStatus); - - if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) - { - return ERROR_BUFFER_TOO_SMALL; - } - else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) - { - return ERROR_INSUFFICIENT_RESOURCES; - } - else - { - return lastErrorStatus; - } -} - -static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) -{ - emergency_recovery(NULL); -} - -static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting init modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_initiator_modes = modes; -} - -static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, - jint modes) -{ - ALOGE("Setting target modes to %x", modes); - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - nat->p2p_target_modes = modes; -} - -static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { - bool result = FALSE; - int load_result; - bool wasDisabled = FALSE; - uint8_t OutputBuffer[1]; - uint8_t InputBuffer[1]; - NFCSTATUS status = NFCSTATUS_FAILED; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - result = FALSE; - goto clean_and_return; - } - - if (takeLock) - { - CONCURRENCY_LOCK(); - } - - /* Initialize Driver */ - if(!driverConfigured) - { - result = nfc_jni_configure_driver(nat); - wasDisabled = TRUE; - } - TRACE("com_android_nfc_NfcManager_doDownload()"); - - TRACE("Go in Download Mode"); - phLibNfc_Download_Mode(); - - TRACE("Load new Firmware Image"); - load_result = phLibNfc_Load_Firmware_Image(); - if(load_result != 0) - { - TRACE("Load new Firmware Image - status = %d",load_result); - result = FALSE; - goto clean_and_return; - } - - // Download - gInputParam.buffer = InputBuffer; - gInputParam.length = 0x01; - gOutputParam.buffer = OutputBuffer; - gOutputParam.length = 0x01; - - ALOGD("Download new Firmware"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - result = FALSE; - goto clean_and_return; - } - - /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we - try to download an old-style firmware on top of a new-style - firmware. Hence, this is expected behavior, and not an - error condition. */ - if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - result = FALSE; - goto clean_and_return; - } - - if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) - { - ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); - } - - /*Download is successful*/ - result = TRUE; -clean_and_return: - TRACE("phLibNfc_HW_Reset()"); - phLibNfc_HW_Reset(); - /* Deinitialize Driver */ - if(wasDisabled) - { - result = nfc_jni_unconfigure_driver(nat); - } - if (takeLock) - { - CONCURRENCY_UNLOCK(); - } - nfc_cb_data_deinit(&cb_data); - return result; -} - -static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) -{ - struct nfc_jni_native_data *nat = NULL; - nat = nfc_jni_get_nat(e, o); - return performDownload(nat, true); -} - -static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) -{ - char buffer[100]; - snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); - return e->NewStringUTF(buffer); -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doDownload", "()Z", - (void *)com_android_nfc_NfcManager_doDownload}, - - {"initializeNativeStructure", "()Z", - (void *)com_android_nfc_NfcManager_init_native_struc}, - - {"doInitialize", "()Z", - (void *)com_android_nfc_NfcManager_initialize}, - - {"doDeinitialize", "()Z", - (void *)com_android_nfc_NfcManager_deinitialize}, - - {"enableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_enableDiscovery}, - - {"doGetSecureElementList", "()[I", - (void *)com_android_nfc_NfcManager_doGetSecureElementList}, - - {"doSelectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doSelectSecureElement}, - - {"doDeselectSecureElement", "()V", - (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, - - {"doCheckLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doCheckLlcp}, - - {"doActivateLlcp", "()Z", - (void *)com_android_nfc_NfcManager_doActivateLlcp}, - - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", - (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, - - {"doGetLastError", "()I", - (void *)com_android_nfc_NfcManager_doGetLastError}, - - {"disableDiscovery", "()V", - (void *)com_android_nfc_NfcManager_disableDiscovery}, - - {"doSetTimeout", "(II)Z", - (void *)com_android_nfc_NfcManager_doSetTimeout}, - - {"doGetTimeout", "(I)I", - (void *)com_android_nfc_NfcManager_doGetTimeout}, - - {"doResetTimeouts", "()V", - (void *)com_android_nfc_NfcManager_doResetTimeouts}, - - {"doAbort", "()V", - (void *)com_android_nfc_NfcManager_doAbort}, - - {"doSetP2pInitiatorModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, - - {"doSetP2pTargetModes","(I)V", - (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, - - {"doDump", "()Ljava/lang/String;", - (void *)com_android_nfc_NfcManager_doDump}, -}; - - -int register_com_android_nfc_NativeNfcManager(JNIEnv *e) -{ - nfc_jni_native_monitor_t *nfc_jni_native_monitor; - - nfc_jni_native_monitor = nfc_jni_init_monitor(); - if(nfc_jni_native_monitor == NULL) - { - ALOGE("NFC Manager cannot recover native monitor %x\n", errno); - return -1; - } - - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", - gMethods, NELEM(gMethods)); -} - -} /* namespace android */ diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp deleted file mode 100755 index bf0bffc..0000000 --- a/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ /dev/null @@ -1,770 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "com_android_nfc.h" - -static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; -static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; -static phNfc_sRemoteDevInformation_t* SecureElementInfo; -static int secureElementHandle; -extern void *gHWRef; -static int SecureElementTech; -extern uint8_t device_connected_flag; - -namespace android { - -static void com_android_nfc_jni_ioctl_callback ( void* pContext, - phNfc_sData_t* Outparam_Cb, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if (status == NFCSTATUS_SUCCESS ) - { - LOG_CALLBACK("> IOCTL successful",status); - } - else - { - LOG_CALLBACK("> IOCTL error",status); - } - - com_android_nfc_jni_ioctl_buffer = Outparam_Cb; - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); - - com_android_nfc_jni_transceive_buffer = pResBuffer; - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static void com_android_nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -/* Set Secure Element mode callback*/ -static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, - phLibNfc_Handle hSecureElement, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - - if(status==NFCSTATUS_SUCCESS) - { - LOG_CALLBACK("SE Set Mode is Successful",status); - TRACE("SE Handle: %lu", hSecureElement); - } - else - { - LOG_CALLBACK("SE Set Mode is failed\n ",status); - } - - pContextData->status = status; - sem_post(&pContextData->sem); -} - -static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, - phLibNfc_RemoteDevList_t *psRemoteDevList, - uint8_t uNofRemoteDev, - NFCSTATUS status) -{ - struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; - NFCSTATUS ret; - int i; - JNIEnv *e = nfc_get_env(); - - if(status == NFCSTATUS_DESELECTED) - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); - } - else - { - LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); - TRACE("Discovered %d secure elements", uNofRemoteDev); - - if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) - { - bool foundHandle = false; - TRACE("Multiple Protocol supported\n"); - for (i=0; iRemDevType); - if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { - secureElementHandle = psRemoteDevList[i].hTargetDev; - foundHandle = true; - } - } - if (!foundHandle) { - ALOGE("Could not find ISO-DEP secure element"); - status = NFCSTATUS_FAILED; - goto clean_and_return; - } - } - else - { - secureElementHandle = psRemoteDevList->hTargetDev; - } - - TRACE("Secure Element Handle: 0x%08x", secureElementHandle); - - /* Set type name */ - jintArray techList; - nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); - - // TODO: Should use the "connected" technology, for now use the first - if ((techList != NULL) && e->GetArrayLength(techList) > 0) { - e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); - TRACE("Store Secure Element Info\n"); - SecureElementInfo = psRemoteDevList->psRemoteDevInfo; - - TRACE("Discovered secure element: tech=%d", SecureElementTech); - } - else { - ALOGE("Discovered secure element, but could not resolve tech"); - status = NFCSTATUS_FAILED; - } - - // This thread may not return to the virtual machine for a long time - // so make sure to delete the local refernce to the tech list. - e->DeleteLocalRef(techList); - } - -clean_and_return: - pContextData->status = status; - sem_post(&pContextData->sem); -} - - -static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) -{ - NFCSTATUS ret; - int semResult; - - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - phLibNfc_sADD_Cfg_t discovery_cfg; - phLibNfc_Registry_Info_t registry_info; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - uint8_t Output_Buff[10]; - uint8_t reg_value; - uint8_t mask_value; - struct nfc_jni_callback_data cb_data; - struct nfc_jni_callback_data cb_data_SE_Notification; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) - { - goto clean_and_return; - } - - /* Registery */ - registry_info.MifareUL = TRUE; - registry_info.MifareStd = TRUE; - registry_info.ISO14443_4A = TRUE; - registry_info.ISO14443_4B = TRUE; - registry_info.Jewel = TRUE; - registry_info.Felica = TRUE; - registry_info.NFC = FALSE; - - CONCURRENCY_LOCK(); - - TRACE("Open Secure Element"); - - /* Check if NFC device is already connected to a tag or P2P peer */ - if (device_connected_flag == 1) - { - ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); - goto clean_and_return; - } - - /* Test if External RF field is detected */ - InParam.buffer = ExternalRFDetected; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - /* Check the value */ - reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; - mask_value = reg_value & 0x40; - - if(mask_value == 0x40) - { - // There is an external RF field present, fail the open request - ALOGD("Unable to open SE connection, external RF Field detected"); - goto clean_and_return; - } - - /* Get Secure Element List */ - TRACE("phLibNfc_SE_GetSecureElementList()"); - ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); - if (ret == NFCSTATUS_SUCCESS) - { - TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); - /* Display Secure Element information */ - for (i = 0; i SMX detected"); - TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); - /* save SMARTMX index */ - SmartMX_detected = 1; - SmartMX_index = i; - } - } - - if(SmartMX_detected) - { - REENTRANCE_LOCK(); - TRACE("phLibNfc_RemoteDev_NtfRegister()"); - ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, - com_android_nfc_jni_open_secure_element_notification_callback, - (void *)&cb_data_SE_Notification); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_SUCCESS) - { - ALOGE("Register Notification error"); - goto clean_and_return; - } - - /* Set wired mode */ - REENTRANCE_LOCK(); - TRACE("phLibNfc_SE_SetMode: Wired mode"); - ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, - phLibNfc_SE_ActModeWired, - com_android_nfc_jni_smartMX_setModeCb, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if (ret != NFCSTATUS_PENDING ) - { - ALOGE("\n> SE Set SmartMX mode ERROR \n" ); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("SE set mode failed"); - goto clean_and_return; - } - - TRACE("Waiting for notification"); - /* Wait for callback response */ - if(sem_wait(&cb_data_SE_Notification.sem)) - { - ALOGE("Secure Element opening error"); - goto clean_and_return; - } - - if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && - cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) - { - ALOGE("SE detection failed"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Connect Tag */ - CONCURRENCY_LOCK(); - TRACE("phLibNfc_RemoteDev_Connect(SMX)"); - REENTRANCE_LOCK(); - ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("CONNECT semaphore error"); - goto clean_and_return; - } - - /* Connect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("Secure Element connect error"); - goto clean_and_return; - } - - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue | 0x40); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(ret!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - /* Return the Handle of the SecureElement */ - return secureElementHandle; - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); - goto clean_and_return; - } - } - else - { - ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - nfc_cb_data_deinit(&cb_data_SE_Notification); - - CONCURRENCY_UNLOCK(); - return 0; -} - - -static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) -{ - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; - uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; - uint32_t SmartMX_Handle; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t InParam; - phNfc_sData_t OutParam; - uint8_t Output_Buff[10]; - uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; - uint8_t GpioSetValue[4]; - uint8_t gpioValue; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Close Secure element function "); - - CONCURRENCY_LOCK(); - /* Disconnect */ - TRACE("Disconnecting from SMX (handle = 0x%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, - NFC_SMARTMX_RELEASE, - com_android_nfc_jni_disconnect_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("\n> Disconnect SE ERROR \n" ); - goto clean_and_return; - } - CONCURRENCY_UNLOCK(); - - /* Get GPIO information */ - CONCURRENCY_LOCK(); - InParam.buffer = GpioGetValue; - InParam.length = 3; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; - TRACE("GpioValue = Ox%02x",gpioValue); - - /* Set GPIO information */ - GpioSetValue[0] = 0x00; - GpioSetValue[1] = 0xF8; - GpioSetValue[2] = 0x2B; - GpioSetValue[3] = (gpioValue & 0xBF); - - TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); - - for(i=0;i<4;i++) - { - TRACE("0x%02x",GpioSetValue[i]); - } - - InParam.buffer = GpioSetValue; - InParam.length = 4; - OutParam.buffer = Output_Buff; - TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); - REENTRANCE_LOCK(); - status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status!=NFCSTATUS_PENDING) - { - ALOGE("IOCTL status error"); - goto clean_and_return; - } - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("IOCTL semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("READ MEM ERROR"); - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, - jobject o,jint handle, jbyteArray data) -{ - uint8_t offset = 0; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - - int tech = SecureElementTech; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - TRACE("Exchange APDU function "); - - CONCURRENCY_LOCK(); - - TRACE("Secure Element tech: %d\n", tech); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - /* Prepare transceive info structure */ - if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) - { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - else if(tech == TARGET_TYPE_ISO14443_4) - { - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - } - - transceive_info.sSendData.buffer = buf + offset; - transceive_info.sSendData.length = buflen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - com_android_nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("TRANSCEIVE semaphore error"); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - ALOGE("TRANSCEIVE error"); - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); - if(result != NULL) - { - e->SetByteArrayRegion(result, 0, - com_android_nfc_jni_transceive_buffer->length, - (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) -{ - TRACE("Get Secure element UID function "); - jbyteArray SecureElementUid; - - if(handle == secureElementHandle) - { - SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); - e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); - return SecureElementUid; - } - else - { - return NULL; - } -} - -static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) -{ - jintArray techList; - TRACE("Get Secure element Type function "); - - if(handle == secureElementHandle) - { - techList = e->NewIntArray(1); - e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); - return techList; - } - else - { - return NULL; - } -} - - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doNativeOpenSecureElementConnection", "()I", - (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, - {"doNativeDisconnectSecureElementConnection", "(I)Z", - (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, - {"doTransceive", "(I[B)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, - {"doGetUid", "(I)[B", - (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, - {"doGetTechList", "(I)[I", - (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, -}; - -int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp deleted file mode 100644 index dbf8dc9..0000000 --- a/jni/com_android_nfc_NativeNfcTag.cpp +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" -#include "phNfcHalTypes.h" - -static phLibNfc_Data_t nfc_jni_ndef_rw; -static phLibNfc_Handle handle; -uint8_t *nfc_jni_ndef_buf = NULL; -uint32_t nfc_jni_ndef_buf_len = 0; - -extern uint8_t device_connected_flag; - -namespace android { - -extern phLibNfc_Handle storedHandle; - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); -extern void nfc_jni_reset_timeout_values(); - -/* - * Callbacks - */ - static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_tag_rw_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - if (pCallbackData->pContext != NULL) { - // Store the remote dev info ptr in the callback context - // Note that this ptr will remain valid, it is tied to a statically - // allocated buffer in libnfc. - phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = - (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; - *ppRemoteDevInfo = psRemoteDevInfo; - } - - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_checkndef_callback(void *pContext, - phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_checkndef_callback", status); - phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); - if(status == NFCSTATUS_OK) - { - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; - nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); - if (pNdefInfo != NULL) *pNdefInfo = info; - } - else { - if (pNdefInfo != NULL) { - memset(pNdefInfo, 0, sizeof(*pNdefInfo)); - } - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_async_disconnect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); - - if(nfc_jni_ndef_buf) - { - free(nfc_jni_ndef_buf); - } - nfc_jni_ndef_buf = NULL; - nfc_jni_ndef_buf_len = 0; -} - -static phNfc_sData_t *nfc_jni_transceive_buffer; - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - nfc_jni_transceive_buffer = pResBuffer; - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presencecheck_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_formatndef_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_readonly_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* Functions */ -static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, - jobject o) -{ - NFCSTATUS status; - phLibNfc_Handle handle = 0; - jbyteArray buf = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; - nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; - - TRACE("phLibNfc_Ndef_Read()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, - phLibNfc_Ndef_EBegin, - nfc_jni_tag_rw_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - buf = e->NewByteArray(nfc_jni_ndef_rw.length); - e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, - (jbyte *)nfc_jni_ndef_rw.buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - - return buf; -} - - -static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, - jobject o, jbyteArray buf) -{ - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); - nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_Ndef_Write()"); - TRACE("Ndef Handle :0x%x\n",handle); - TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * Utility to recover poll bytes from target infos - */ -static void set_target_pollBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); - - jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingPollBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - jint *techId = e->GetIntArrayElements(techList, 0); - int techListLength = e->GetArrayLength(techList); - - jbyteArray pollBytes = e->NewByteArray(0); - jobjectArray techPollBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(pollBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) - { - /* ISO14443-3A: ATQA/SENS_RES */ - case TARGET_TYPE_ISO14443_3A: - if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { - // Jewel ATQA is not read and stored by the PN544, but it is fixed - // at {0x00, 0x0C} in the spec. So eJewel can safely be - // translated to {0x00, 0x0C}. - const static jbyte JewelAtqA[2] = {0x00, 0x0C}; - pollBytes = e->NewByteArray(2); - e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); - } - else { - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); - } - break; - /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ - case TARGET_TYPE_ISO14443_3B: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); - break; - /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ - case TARGET_TYPE_FELICA: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), - sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - pollBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techPollBytes, tech, pollBytes); - } - - e->SetObjectField(tag, f, techPollBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); - -} - -/* - * Utility to recover activation bytes from target infos - */ -static void set_target_activationBytes(JNIEnv *e, jobject tag, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) -{ - jclass tag_cls = e->GetObjectClass(tag); - - jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); - jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); - - if (existingActBytes != NULL) { - return; - } - - jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); - jintArray techList = (jintArray) e->GetObjectField(tag, techListField); - int techListLength = e->GetArrayLength(techList); - jint *techId = e->GetIntArrayElements(techList, 0); - - jbyteArray actBytes = e->NewByteArray(0); - jobjectArray techActBytes = e->NewObjectArray(techListLength, - e->GetObjectClass(actBytes), 0); - - for (int tech = 0; tech < techListLength; tech++) { - switch(techId[tech]) { - - /* ISO14443-3A: SAK/SEL_RES */ - case TARGET_TYPE_ISO14443_3A: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); - break; - /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ - /* ISO14443-3B & ISO14443-4: HiLayerResp */ - case TARGET_TYPE_ISO14443_4: - // Determine whether -A or -B - if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); - e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); - } - else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || - psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { - actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); - e->SetByteArrayRegion(actBytes, 0, - psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, - (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); - } - break; - /* ISO15693: response flags (1 byte), DSFID (1 byte) */ - case TARGET_TYPE_ISO15693: - actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) - + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); - e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); - e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), - sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), - (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); - break; - default: - actBytes = e->NewByteArray(0); - break; - } - e->SetObjectArrayElement(techActBytes, tech, actBytes); - } - e->SetObjectField(tag, f, techActBytes); - - e->ReleaseIntArrayElements(techList, techId, 0); -} - -static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - // Success, set poll & act bytes - set_target_pollBytes(e, o, pRemDevInfo); - set_target_activationBytes(e, o, pRemDevInfo); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, - jobject o, phLibNfc_Handle handle) -{ - jclass cls; - jfieldID f; - jint status; - struct nfc_jni_callback_data cb_data; - phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); - REENTRANCE_LOCK(); - storedHandle = handle; - status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - - /* Connect Status */ - if(status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, - jobject o) -{ - // Reconnect is provided by libnfc by just calling connect again - // on the same handle. - int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - if (libNfcType != -1) { - // Note that some tag types are stateless, hence we do not reconnect - // those. Currently those are the Jewel and Iso15693 technologies. - if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); - return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); - } - else { - return NFCSTATUS_SUCCESS; - } - } - else { - return NFCSTATUS_REJECTED; - } -} - - -static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jclass cls; - jfieldID f; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_connected_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Reset the stored handle */ - storedHandle = 0; - - nfc_jni_reset_timeout_values(); - - /* Disconnect */ - TRACE("Disconnecting from tag (%x)", handle); - - if (handle == -1) { - // Was never connected to any tag, exit - result = JNI_TRUE; - ALOGE("doDisconnect() - Target already disconnected"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, - nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - result = JNI_TRUE; - TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); - goto clean_and_return; - } - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static uint16_t -crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) -{ - uint16_t b, crc = init; - - do { - b = *msg++ ^ (crc & 0xFF); - b ^= (b << 4) & 0xFF; - crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); - } while( --len ); - - return crc; -} - -static void -nfc_insert_crc_a( uint8_t* msg, size_t len ) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - msg[len] = crc & 0xFF; - msg[len + 1] = (crc >> 8) & 0xFF; -} - -static void -nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) -{ - uint16_t crc; - - crc = crc_16_ccitt1( msg, len, 0x6363 ); - *byte1 = crc & 0xFF; - *byte2 = (crc >> 8) & 0xFF; -} - -static bool -crc_valid( uint8_t* msg, size_t len) -{ - uint8_t crcByte1, crcByte2; - - nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, - len - 2, &crcByte1, &crcByte2); - - if (msg[len - 2] == crcByte1 && - msg[len - 1] == crcByte2) { - return true; - } - else { - return false; - } - -} - -static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, - jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) -{ - uint8_t offset = 0; - // buf is the pointer to the JNI array and never overwritten, - // outbuf is passed into the transceive - it may be pointed to new memory - // to be extended with CRC. - uint8_t *buf = NULL; - uint32_t buflen; - - uint8_t *outbuf = NULL; - uint32_t outlen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - int res; - phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - int selectedTech = 0; - int selectedLibNfcType = 0; - jint* technologies = NULL; - bool checkResponseCrc = false; - - jint *targetLost; - if (statusTargetLost != NULL) { - targetLost = e->GetIntArrayElements(statusTargetLost, 0); - if (targetLost != NULL) { - *targetLost = 0; - } - } else { - targetLost = NULL; - } - - memset(&transceive_info, 0, sizeof(transceive_info)); - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - selectedTech = nfc_jni_get_connected_technology(e, o); - selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); - - buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = outlen = (uint32_t)e->GetArrayLength(data); - - switch (selectedTech) { - case TARGET_TYPE_FELICA: - transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_MIFARE_CLASSIC: - case TARGET_TYPE_MIFARE_UL: - if (raw) { - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - break; - case TARGET_TYPE_ISO14443_3A: - // Check which libnfc type - if (selectedLibNfcType == phNfc_eJewel_PICC) { - // For the Jewel pipe, CRC is automatically computed - transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; - transceive_info.addr = 0; - } else { - if (raw) { - // Use Mifare Raw to implement a standard - // ISO14443-3A transceive, with CRC added - transceive_info.cmd.MfCmd = phHal_eMifareRaw; - transceive_info.addr = 0; - // Need to add in the crc here - outbuf = (uint8_t*)malloc(buflen + 2); - outlen += 2; - memcpy(outbuf, buf, buflen); - nfc_insert_crc_a(outbuf, buflen); - - checkResponseCrc = true; - } else { - // Use the mifare pipe - offset = 2; - transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; - transceive_info.addr = (uint8_t)buf[1]; - } - - } - break; - case TARGET_TYPE_ISO14443_4: - transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; - transceive_info.addr = 0; - break; - case TARGET_TYPE_ISO15693: - transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; - transceive_info.addr = 0; - break; - case TARGET_TYPE_UNKNOWN: - case TARGET_TYPE_ISO14443_3B: - // Not supported - goto clean_and_return; - default: - break; - } - - transceive_info.sSendData.buffer = outbuf + offset; - transceive_info.sSendData.length = outlen - offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, - nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { - *targetLost = 1; - } - goto clean_and_return; - } - - /* Copy results back to Java * - * In case of NfcA and raw, also check the CRC in the response - * and cut it off in the returned data. - */ - if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { - if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { - result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length - 2, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } - } else { - result = e->NewByteArray(nfc_jni_transceive_buffer->length); - if (result != NULL) { - e->SetByteArrayRegion(result, 0, - nfc_jni_transceive_buffer->length, - (jbyte *)nfc_jni_transceive_buffer->buffer); - } - } -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - if ((outbuf != buf) && (outbuf != NULL)) { - // Buf was extended and re-alloced with crc bytes, free separately - free(outbuf); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)buf, JNI_ABORT); - - if (targetLost != NULL) { - e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); - } - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, - jint libnfcType, jint javaType) -{ - jint ndefType = NDEF_UNKNOWN_TYPE; - - switch (libnfcType) { - case phNfc_eJewel_PICC: - ndefType = NDEF_TYPE1_TAG; - break; - case phNfc_eISO14443_3A_PICC: - ndefType = NDEF_TYPE2_TAG;; - break; - case phNfc_eFelica_PICC: - ndefType = NDEF_TYPE3_TAG; - break; - case phNfc_eISO14443_A_PICC: - case phNfc_eISO14443_4A_PICC: - case phNfc_eISO14443_B_PICC: - case phNfc_eISO14443_4B_PICC: - ndefType = NDEF_TYPE4_TAG; - break; - case phNfc_eMifare_PICC: - if (javaType == TARGET_TYPE_MIFARE_UL) { - ndefType = NDEF_TYPE2_TAG; - } else { - ndefType = NDEF_MIFARE_CLASSIC_TAG; - } - break; - case phNfc_eISO15693_PICC: - ndefType = NDEF_ICODE_SLI_TAG; - break; - default: - ndefType = NDEF_UNKNOWN_TYPE; - break; - } - return ndefType; -} - -static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) -{ - phLibNfc_Handle handle = 0; - jint status; - phLibNfc_ChkNdef_Info_t sNdefInfo; - struct nfc_jni_callback_data cb_data; - jint *ndef = e->GetIntArrayElements(ndefinfo, 0); - int apiCardState = NDEF_MODE_UNKNOWN; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - status = NFCSTATUS_NOT_ENOUGH_MEMORY; - goto clean_and_return; - } - cb_data.pContext = &sNdefInfo; - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_Ndef_CheckNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - status = NFCSTATUS_ABORTED; - goto clean_and_return; - } - - status = cb_data.status; - TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); - - if (status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - ndef[0] = sNdefInfo.MaxNdefMsgLength; - // Translate the card state to know values for the NFC API - switch (sNdefInfo.NdefCardState) { - case PHLIBNFC_NDEF_CARD_INITIALISED: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_READ_ONLY: - apiCardState = NDEF_MODE_READ_ONLY; - break; - case PHLIBNFC_NDEF_CARD_READ_WRITE: - apiCardState = NDEF_MODE_READ_WRITE; - break; - case PHLIBNFC_NDEF_CARD_INVALID: - apiCardState = NDEF_MODE_UNKNOWN; - break; - } - ndef[1] = apiCardState; - -clean_and_return: - e->ReleaseIntArrayElements(ndefinfo, ndef, 0); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return status; -} - -static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - TRACE("phLibNfc_RemoteDev_CheckPresence()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, - jobject o, jbyteArray pollBytes, jbyteArray actBytes) -{ - // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire - // is supported. - jboolean result = JNI_FALSE; - - // DESfire has one sak byte and 2 ATQA bytes - if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && - actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { - jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); - jbyte* act = e->GetByteArrayElements(actBytes, NULL); - if (act[0] == 0x20 && poll[1] == 0x03) { - uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; - // Identifies as DESfire, use get version cmd to be sure - jbyteArray versionCmd = e->NewByteArray(5); - e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); - jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, - versionCmd, JNI_TRUE, NULL); - if (respBytes != NULL) { - // Check whether the response matches a typical DESfire - // response. - // libNFC even does more advanced checking than we do - // here, and will only format DESfire's with a certain - // major/minor sw version and NXP as a manufacturer. - // We don't want to do such checking here, to avoid - // having to change code in multiple places. - // A succesful (wrapped) DESFire getVersion command returns - // 9 bytes, with byte 7 0x91 and byte 8 having status - // code 0xAF (these values are fixed and well-known). - int respLength = e->GetArrayLength(respBytes); - jbyte* resp = e->GetByteArrayElements(respBytes, NULL); - if (respLength == 9 && resp[7] == (jbyte)0x91 && - resp[8] == (jbyte)0xAF) { - result = JNI_TRUE; - } - e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); - } - } - e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); - e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); - } - - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - phNfc_sData_t keyBuffer; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_RemoteDev_FormatNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - phNfc_sData_t keyBuffer; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - handle = nfc_jni_get_connected_handle(e, o); - keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); - keyBuffer.length = e->GetArrayLength(key); - TRACE("phLibNfc_ConvertToReadOnlyNdef()"); - REENTRANCE_LOCK(); - status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, - (void *)&cb_data); - REENTRANCE_UNLOCK(); - - if(status != NFCSTATUS_PENDING) - { - ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if (cb_data.status == NFCSTATUS_SUCCESS) - { - result = JNI_TRUE; - } - -clean_and_return: - e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeNfcTag_doDisconnect}, - {"doReconnect", "()I", - (void *)com_android_nfc_NativeNfcTag_doReconnect}, - {"doHandleReconnect", "(I)I", - (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, - {"doTransceive", "([BZ[I)[B", - (void *)com_android_nfc_NativeNfcTag_doTransceive}, - {"doGetNdefType", "(II)I", - (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, - {"doCheckNdef", "([I)I", - (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, - {"doRead", "()[B", - (void *)com_android_nfc_NativeNfcTag_doRead}, - {"doWrite", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doWrite}, - {"doPresenceCheck", "()Z", - (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, - {"doIsIsoDepNdefFormatable", "([B[B)Z", - (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, - {"doNdefFormat", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, - {"doMakeReadonly", "([B)Z", - (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, -}; - -int register_com_android_nfc_NativeNfcTag(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", - gMethods, NELEM(gMethods)); -} - -} // namespace android diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp deleted file mode 100644 index b3cc6e3..0000000 --- a/jni/com_android_nfc_NativeP2pDevice.cpp +++ /dev/null @@ -1,490 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "com_android_nfc.h" - -extern uint8_t device_connected_flag; - -namespace android { - -extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); - -/* - * Callbacks - */ -static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_presence_check_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_connect_callback(void *pContext, - phLibNfc_Handle hRemoteDev, - phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_connect_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; - psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); - psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_disconnect_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; - LOG_CALLBACK("nfc_jni_receive_callback", status); - - if(status == NFCSTATUS_SUCCESS) - { - *ptr = data; - } - else - { - *ptr = NULL; - } - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_send_callback", status); - - /* Report the callback status and wake up the caller */ - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -/* - * Functions - */ - -static void nfc_jni_transceive_callback(void *pContext, - phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) -{ - struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; - LOG_CALLBACK("nfc_jni_transceive_callback", status); - - /* Report the callback data and wake up the caller */ - pCallbackData->pContext = pResBuffer; - pCallbackData->status = status; - sem_post(&pCallbackData->sem); -} - -static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - NFCSTATUS status; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - jclass target_cls = NULL; - jobject tag; - jmethodID ctor; - jfieldID f; - jbyteArray generalBytes = NULL; - phNfc_sData_t sGeneralBytes; - unsigned int i; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Connect(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Set General Bytes */ - target_cls = e->GetObjectClass(o); - - f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); - - TRACE("General Bytes Length = %d", sGeneralBytes.length); - TRACE("General Bytes ="); - for(i=0;iNewByteArray(sGeneralBytes.length); - - e->SetByteArrayRegion(generalBytes, 0, - sGeneralBytes.length, - (jbyte *)sGeneralBytes.buffer); - - e->SetObjectField(o, f, generalBytes); - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - /* Restart the polling loop if the connection failed */ - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) -{ - phLibNfc_Handle handle = 0; - jboolean result = JNI_FALSE; - NFCSTATUS status; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Disconnect */ - TRACE("Disconnecting from target (handle = 0x%x)", handle); - - /* NativeNfcTag waits for tag to leave the field here with presence check. - * We do not in P2P path because presence check is not safe while transceive may be - * in progress. - */ - - TRACE("phLibNfc_RemoteDev_Disconnect()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - if(status == NFCSTATUS_TARGET_NOT_CONNECTED) - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); - } - else - { - ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); - nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); - } - - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - /* Disconnect Status */ - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - /* Reset device connected flag */ - device_connected_flag = 0; - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, - jobject o, jbyteArray data) -{ - NFCSTATUS status; - uint8_t offset = 2; - uint8_t *buf; - uint32_t buflen; - phLibNfc_sTransceiveInfo_t transceive_info; - jbyteArray result = NULL; - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - phNfc_sData_t * receive_buffer = NULL; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) - { - goto clean_and_return; - } - - /* Transceive*/ - TRACE("Transceive data to target (handle = 0x%x)", handle); - - buf = (uint8_t *)e->GetByteArrayElements(data, NULL); - buflen = (uint32_t)e->GetArrayLength(data); - - TRACE("Buffer Length = %d\n", buflen); - - transceive_info.sSendData.buffer = buf; //+ offset; - transceive_info.sSendData.length = buflen; //- offset; - transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); - transceive_info.sRecvData.length = 1024; - - if(transceive_info.sRecvData.buffer == NULL) - { - goto clean_and_return; - } - - TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - /* Copy results back to Java */ - result = e->NewByteArray(receive_buffer->length); - if(result != NULL) - e->SetByteArrayRegion(result, 0, - receive_buffer->length, - (jbyte *)receive_buffer->buffer); - -clean_and_return: - if(transceive_info.sRecvData.buffer != NULL) - { - free(transceive_info.sRecvData.buffer); - } - - e->ReleaseByteArrayElements(data, - (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); - - nfc_cb_data_deinit(&cb_data); - - CONCURRENCY_UNLOCK(); - - return result; -} - - -static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( - JNIEnv *e, jobject o) -{ - NFCSTATUS status; - struct timespec ts; - phLibNfc_Handle handle; - jbyteArray buf = NULL; - static phNfc_sData_t *data; - struct nfc_jni_callback_data cb_data; - - CONCURRENCY_LOCK(); - - handle = nfc_jni_get_p2p_device_handle(e, o); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, (void*)data)) - { - goto clean_and_return; - } - - /* Receive */ - TRACE("phLibNfc_RemoteDev_Receive()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(data == NULL) - { - goto clean_and_return; - } - - buf = e->NewByteArray(data->length); - e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); - -clean_and_return: - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return buf; -} - -static jboolean com_android_nfc_NativeP2pDevice_doSend( - JNIEnv *e, jobject o, jbyteArray buf) -{ - NFCSTATUS status; - phNfc_sData_t data; - jboolean result = JNI_FALSE; - struct nfc_jni_callback_data cb_data; - - phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); - - CONCURRENCY_LOCK(); - - /* Create the local semaphore */ - if (!nfc_cb_data_init(&cb_data, NULL)) - { - goto clean_and_return; - } - - /* Send */ - TRACE("Send data to the Initiator (handle = 0x%x)", handle); - - data.length = (uint32_t)e->GetArrayLength(buf); - data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); - - TRACE("phLibNfc_RemoteDev_Send()"); - REENTRANCE_LOCK(); - status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); - REENTRANCE_UNLOCK(); - if(status != NFCSTATUS_PENDING) - { - ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - goto clean_and_return; - } - TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); - - /* Wait for callback response */ - if(sem_wait(&cb_data.sem)) - { - ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); - goto clean_and_return; - } - - if(cb_data.status != NFCSTATUS_SUCCESS) - { - goto clean_and_return; - } - - result = JNI_TRUE; - -clean_and_return: - if (result != JNI_TRUE) - { - e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); - } - nfc_cb_data_deinit(&cb_data); - CONCURRENCY_UNLOCK(); - return result; -} - -/* - * JNI registration. - */ -static JNINativeMethod gMethods[] = -{ - {"doConnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doConnect}, - {"doDisconnect", "()Z", - (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, - {"doTransceive", "([B)[B", - (void *)com_android_nfc_NativeP2pDevice_doTransceive}, - {"doReceive", "()[B", - (void *)com_android_nfc_NativeP2pDevice_doReceive}, - {"doSend", "([B)Z", - (void *)com_android_nfc_NativeP2pDevice_doSend}, -}; - -int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) -{ - return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", - gMethods, NELEM(gMethods)); -} - -} // namepspace android diff --git a/jni/com_android_nfc_list.cpp b/jni/com_android_nfc_list.cpp deleted file mode 100644 index f0487d3..0000000 --- a/jni/com_android_nfc_list.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#undef LOG_TAG -#define LOG_TAG "NFC_LIST" - -bool listInit(listHead* pList) -{ - pList->pFirst = NULL; - if(pthread_mutex_init(&pList->mutex, NULL) == -1) - { - ALOGE("Mutex creation failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listDestroy(listHead* pList) -{ - bool bListNotEmpty = true; - while (bListNotEmpty) { - bListNotEmpty = listGetAndRemoveNext(pList, NULL); - } - - if(pthread_mutex_destroy(&pList->mutex) == -1) - { - ALOGE("Mutex destruction failed (errno=0x%08x)", errno); - return false; - } - - return true; -} - -bool listAdd(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pLastNode; - bool result; - - /* Create node */ - pNode = (struct listNode*)malloc(sizeof(listNode)); - if (pNode == NULL) - { - result = false; - ALOGE("Failed to malloc"); - goto clean_and_return; - } - TRACE("Allocated node: %8p (%8p)", pNode, pData); - pNode->pData = pData; - pNode->pNext = NULL; - - pthread_mutex_lock(&pList->mutex); - - /* Add the node to the list */ - if (pList->pFirst == NULL) - { - /* Set the node as the head */ - pList->pFirst = pNode; - } - else - { - /* Seek to the end of the list */ - pLastNode = pList->pFirst; - while(pLastNode->pNext != NULL) - { - pLastNode = pLastNode->pNext; - } - - /* Add the node to the current list */ - pLastNode->pNext = pNode; - } - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listRemove(listHead* pList, void* pData) -{ - struct listNode* pNode; - struct listNode* pRemovedNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst == NULL) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - pNode = pList->pFirst; - if (pList->pFirst->pData == pData) - { - /* Get the removed node */ - pRemovedNode = pNode; - - /* Remove the first node */ - pList->pFirst = pList->pFirst->pNext; - } - else - { - while (pNode->pNext != NULL) - { - if (pNode->pNext->pData == pData) - { - /* Node found ! */ - break; - } - pNode = pNode->pNext; - } - - if (pNode->pNext == NULL) - { - /* Node not found */ - result = false; - ALOGE("Failed to deallocate (not found %8p)", pData); - goto clean_and_return; - } - - /* Get the removed node */ - pRemovedNode = pNode->pNext; - - /* Remove the node from the list */ - pNode->pNext = pNode->pNext->pNext; - } - - /* Deallocate the node */ - TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); - free(pRemovedNode); - - result = true; - -clean_and_return: - pthread_mutex_unlock(&pList->mutex); - return result; -} - -bool listGetAndRemoveNext(listHead* pList, void** ppData) -{ - struct listNode* pNode; - bool result; - - pthread_mutex_lock(&pList->mutex); - - if (pList->pFirst) - { - /* Empty list */ - ALOGE("Failed to deallocate (list empty)"); - result = false; - goto clean_and_return; - } - - /* Work on the first node */ - pNode = pList->pFirst; - - /* Return the data */ - if (ppData != NULL) - { - *ppData = pNode->pData; - } - - /* Remove and deallocate the node */ - pList->pFirst = pNode->pNext; - TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); - free(pNode); - - result = true; - -clean_and_return: - listDump(pList); - pthread_mutex_unlock(&pList->mutex); - return result; -} - -void listDump(listHead* pList) -{ - struct listNode* pNode = pList->pFirst; - - TRACE("Node dump:"); - while (pNode != NULL) - { - TRACE("- %8p (%8p)", pNode, pNode->pData); - pNode = pNode->pNext; - } -} diff --git a/jni/com_android_nfc_list.h b/jni/com_android_nfc_list.h deleted file mode 100644 index 22b4f09..0000000 --- a/jni/com_android_nfc_list.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COM_ANDROID_NFC_LIST_H__ -#define __COM_ANDROID_NFC_LIST_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct listNode -{ - void* pData; - struct listNode* pNext; -}; - -struct listHead -{ - listNode* pFirst; - pthread_mutex_t mutex; -}; - -bool listInit(listHead* pList); -bool listDestroy(listHead* pList); -bool listAdd(listHead* pList, void* pData); -bool listRemove(listHead* pList, void* pData); -bool listGetAndRemoveNext(listHead* pList, void** ppData); -void listDump(listHead* pList); - -#ifdef __cplusplus -} -#endif - -#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/Android.mk b/nxp/Android.mk new file mode 100644 index 0000000..34f4385 --- /dev/null +++ b/nxp/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH:= $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/nxp/jni/Android.mk b/nxp/jni/Android.mk new file mode 100644 index 0000000..8ae792a --- /dev/null +++ b/nxp/jni/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + + + +LOCAL_SRC_FILES:= \ + com_android_nfc_NativeLlcpConnectionlessSocket.cpp \ + com_android_nfc_NativeLlcpServiceSocket.cpp \ + com_android_nfc_NativeLlcpSocket.cpp \ + com_android_nfc_NativeNfcManager.cpp \ + com_android_nfc_NativeNfcTag.cpp \ + com_android_nfc_NativeP2pDevice.cpp \ + com_android_nfc_NativeNfcSecureElement.cpp \ + com_android_nfc_list.cpp \ + com_android_nfc.cpp + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + external/libnfc-nxp/src \ + external/libnfc-nxp/inc + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + libcutils \ + libutils \ + libnfc \ + libhardware + +#LOCAL_CFLAGS += -O0 -g + +LOCAL_MODULE := libnfc_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nxp/jni/com_android_nfc.cpp b/nxp/jni/com_android_nfc.cpp new file mode 100644 index 0000000..d794d6e --- /dev/null +++ b/nxp/jni/com_android_nfc.cpp @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "errno.h" +#include "com_android_nfc.h" +#include "com_android_nfc_list.h" +#include "phLibNfcStatus.h" + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + JNIEnv *e; + + ALOGD("NFC Service : loading JNI\n"); + + // Check JNI version + if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) + return JNI_ERR; + + android::vm = jvm; + + if (android::register_com_android_nfc_NativeNfcManager(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1) + return JNI_ERR; + + return JNI_VERSION_1_6; +} + +namespace android { + +extern struct nfc_jni_native_data *exported_nat; + +JavaVM *vm; + +/* + * JNI Utils + */ +JNIEnv *nfc_get_env() +{ + JNIEnv *e; + if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) { + ALOGE("Current thread is not attached to VM"); + phLibNfc_Mgt_Recovery(); + abort(); + } + return e; +} + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext) +{ + /* Create semaphore */ + if(sem_init(&pCallbackData->sem, 0, 0) == -1) + { + ALOGE("Semaphore creation failed (errno=0x%08x)", errno); + return false; + } + + /* Set default status value */ + pCallbackData->status = NFCSTATUS_FAILED; + + /* Copy the context */ + pCallbackData->pContext = pContext; + + /* Add to active semaphore list */ + if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to add the semaphore to the list"); + } + + return true; +} + +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData) +{ + /* Destroy semaphore */ + if (sem_destroy(&pCallbackData->sem)) + { + ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno); + } + + /* Remove from active semaphore list */ + if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData)) + { + ALOGE("Failed to remove semaphore from the list"); + } + +} + +void nfc_cb_data_releaseAll() +{ + nfc_jni_callback_data* pCallbackData; + + while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData)) + { + pCallbackData->status = NFCSTATUS_FAILED; + sem_post(&pCallbackData->sem); + } +} + +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj) +{ + jclass cls; + jobject obj; + jmethodID ctor; + + cls = e->FindClass(clsname); + if(cls == NULL) + { + return -1; + ALOGD("Find class error\n"); + } + + + ctor = e->GetMethodID(cls, "", "()V"); + + obj = e->NewObject(cls, ctor); + if(obj == NULL) + { + return -1; + ALOGD("Create object error\n"); + } + + *cached_obj = e->NewGlobalRef(obj); + if(*cached_obj == NULL) + { + e->DeleteLocalRef(obj); + ALOGD("Global ref error\n"); + return -1; + } + + e->DeleteLocalRef(obj); + + return 0; +} + + +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e) +{ + return exported_nat; +} + +static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL; + +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void) +{ + + pthread_mutexattr_t recursive_attr; + + pthread_mutexattr_init(&recursive_attr); + pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP); + + if(nfc_jni_native_monitor == NULL) + { + nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t)); + } + + if(nfc_jni_native_monitor != NULL) + { + memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t)); + + if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1) + { + ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1) + { + ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno); + return NULL; + } + + if(!listInit(&nfc_jni_native_monitor->sem_list)) + { + ALOGE("NFC Manager Semaphore List creation failed"); + return NULL; + } + + LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head); + + if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1) + { + ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno); + return NULL; + } + + if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1) + { + ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno); + return NULL; + } + +} + + return nfc_jni_native_monitor; +} + +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void) +{ + return nfc_jni_native_monitor; +} + + +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mMode", "S"); + + return e->GetShortField(o, f); +} + + +int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o) +{ + + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedTechIndex", "I"); + + return e->GetIntField(o, f); + +} + +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + int connectedTech = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o); + + if ((connectedTechIndex != -1) && (techTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(techTypes))) { + jint* technologies = e->GetIntArrayElements(techTypes, 0); + if (technologies != NULL) { + connectedTech = technologies[connectedTechIndex]; + e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT); + } + } + + return connectedTech; + +} + +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jint connectedLibNfcType = -1; + + int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o); + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechLibNfcTypes", "[I"); + jintArray libNfcTypes = (jintArray) e->GetObjectField(o, f); + + if ((connectedTechIndex != -1) && (libNfcTypes != NULL) && + (connectedTechIndex < e->GetArrayLength(libNfcTypes))) { + jint* types = e->GetIntArrayElements(libNfcTypes, 0); + if (types != NULL) { + connectedLibNfcType = types[connectedTechIndex]; + e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT); + } + } + return connectedLibNfcType; + +} + +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mConnectedHandle", "I"); + + return e->GetIntField(o, f); +} + +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mHandle", "I"); + + return e->GetIntField(o, f); +} + +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o) +{ + jclass c; + jfieldID f; + jintArray techtypes; + + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mTechList","[I"); + + /* Read the techtypes */ + techtypes = (jintArray) e->GetObjectField(o, f); + + return techtypes; +} + + + +//Display status code +const char* nfc_jni_get_status_name(NFCSTATUS status) +{ + #define STATUS_ENTRY(status) { status, #status } + + struct status_entry { + NFCSTATUS code; + const char *name; + }; + + const struct status_entry sNameTable[] = { + STATUS_ENTRY(NFCSTATUS_SUCCESS), + STATUS_ENTRY(NFCSTATUS_FAILED), + STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES), + STATUS_ENTRY(NFCSTATUS_TARGET_LOST), + STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS), + STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED), + STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_SHUTDOWN), + STATUS_ENTRY(NFCSTATUS_ABORTED), + STATUS_ENTRY(NFCSTATUS_REJECTED ), + STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED), + STATUS_ENTRY(NFCSTATUS_PENDING), + STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL), + STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED), + STATUS_ENTRY(NFCSTATUS_BUSY), + STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED), + STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS), + STATUS_ENTRY(NFCSTATUS_DESELECTED), + STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE), + STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION), + STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT), + STATUS_ENTRY(NFCSTATUS_RF_ERROR), + STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR), + STATUS_ENTRY(NFCSTATUS_INVALID_STATE), + STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED), + STATUS_ENTRY(NFCSTATUS_RELEASED), + STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED), + STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE), + STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED), + STATUS_ENTRY(NFCSTATUS_READ_FAILED), + STATUS_ENTRY(NFCSTATUS_WRITE_FAILED), + STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT), + STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED), + STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH), + STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT), + STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE), + STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR), + }; + + int i = sizeof(sNameTable)/sizeof(status_entry); + + while(i>0) + { + i--; + if (sNameTable[i].code == PHNFCSTATUS(status)) + { + return sNameTable[i].name; + } + } + + return "UNKNOWN"; +} + +int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize, + int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) { + bool found = false; + for (int i = 0; i < listSize; i++) { + if (techList[i] == techToAdd) { + found = true; + break; + } + } + if (!found && listSize < maxListSize) { + techList[listSize] = techToAdd; + handleList[listSize] = handleToAdd; + typeList[listSize] = typeToAdd; + return listSize + 1; + } + else { + return listSize; + } +} + + +#define MAX_NUM_TECHNOLOGIES 32 + +/* + * Utility to get a technology tree and a corresponding handle list from a detected tag. + */ +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* libnfcTypeList) +{ + int technologies[MAX_NUM_TECHNOLOGIES]; + int handles[MAX_NUM_TECHNOLOGIES]; + int libnfctypes[MAX_NUM_TECHNOLOGIES]; + + int index = 0; + // TODO: This counts from up to down because on multi-protocols, the + // ISO handle is usually the second, and we prefer the ISO. Should implement + // a method to find the "preferred handle order" and use that instead, + // since we shouldn't have dependencies on the tech list ordering. + for (int target = count - 1; target >= 0; target--) { + int type = devList[target].psRemoteDevInfo->RemDevType; + int handle = devList[target].hTargetDev; + switch (type) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + break; + } + case phNfc_eISO14443_4B_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, index, + MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO14443_3A_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + case phNfc_eISO14443_B_PICC: + { + // TODO a bug in libnfc will cause 14443-3B only cards + // to be returned as this type as well, but these cards + // are very rare. Hence assume it's -4B + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type); + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type); + }break; + case phNfc_eISO15693_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type); + }break; + case phNfc_eMifare_PICC: + { + // We don't want to be too clever here; libnfc has already determined + // it's a Mifare, so we only check for UL, for all other tags + // we assume it's a mifare classic. This should make us more + // future-proof. + int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak; + switch(sak) + { + case 0x00: + // could be UL or UL-C + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type); + break; + default: + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type); + break; + } + }break; + case phNfc_eFelica_PICC: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type); + }break; + case phNfc_eJewel_PICC: + { + // Jewel represented as NfcA + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type); + }break; + default: + { + index = addTechIfNeeded(technologies, handles, libnfctypes, + index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type); + } + } + } + + // Build the Java arrays + if (techList != NULL) { + *techList = e->NewIntArray(index); + e->SetIntArrayRegion(*techList, 0, index, technologies); + } + + if (handleList != NULL) { + *handleList = e->NewIntArray(index); + e->SetIntArrayRegion(*handleList, 0, index, handles); + } + + if (libnfcTypeList != NULL) { + *libnfcTypeList = e->NewIntArray(index); + e->SetIntArrayRegion(*libnfcTypeList, 0, index, libnfctypes); + } +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h new file mode 100644 index 0000000..a44bcf0 --- /dev/null +++ b/nxp/jni/com_android_nfc.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_JNI_H__ +#define __COM_ANDROID_NFC_JNI_H__ + +#define LOG_TAG "NFCJNI" + +#include +#include + +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include + +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 + +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 +#define NDEF_ICODE_SLI_TAG 102 + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ + +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + +#define SMX_SECURE_ELEMENT_ID 11259375 + +/* Maximum byte length of an AID. */ +#define AID_MAXLEN 16 + +/* Utility macros for logging */ +#define GET_LEVEL(status) ((status)==NFCSTATUS_SUCCESS)?ANDROID_LOG_DEBUG:ANDROID_LOG_WARN + +#if 0 + #define LOG_CALLBACK(funcName, status) LOG_PRI(GET_LEVEL(status), LOG_TAG, "Callback: %s() - status=0x%04x[%s]", funcName, status, nfc_jni_get_status_name(status)); + #define TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#else + #define LOG_CALLBACK(...) + #define TRACE(...) +#endif + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Target discovery configuration */ + int discovery_modes_state[DISCOVERY_MODE_TABLE_SIZE]; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + /* Tag detected */ + jobject tag; + + /* Lib Status */ + NFCSTATUS status; + + /* p2p modes */ + int p2p_initiator_modes; + int p2p_target_modes; + +}; + +typedef struct nfc_jni_native_monitor +{ + /* Mutex protecting native library against reentrance */ + pthread_mutex_t reentrance_mutex; + + /* Mutex protecting native library against concurrency */ + pthread_mutex_t concurrency_mutex; + + /* List used to track pending semaphores waiting for callback */ + struct listHead sem_list; + + /* List used to track incoming socket requests (and associated sync variables) */ + LIST_HEAD(, nfc_jni_listen_data) incoming_socket_head; + pthread_mutex_t incoming_socket_mutex; + pthread_cond_t incoming_socket_cond; + +} nfc_jni_native_monitor_t; + +typedef struct nfc_jni_callback_data +{ + /* Semaphore used to wait for callback */ + sem_t sem; + + /* Used to store the status sent by the callback */ + NFCSTATUS status; + + /* Used to provide a local context to the callback */ + void* pContext; + +} nfc_jni_callback_data_t; + +typedef struct nfc_jni_listen_data +{ + /* LLCP server socket receiving the connection request */ + phLibNfc_Handle pServerSocket; + + /* LLCP socket created from the connection request */ + phLibNfc_Handle pIncomingSocket; + + /* List entries */ + LIST_ENTRY(nfc_jni_listen_data) entries; + +} nfc_jni_listen_data_t; + +/* TODO: treat errors and add traces */ +#define REENTRANCE_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->reentrance_mutex) +#define REENTRANCE_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->reentrance_mutex) +#define CONCURRENCY_LOCK() pthread_mutex_lock(&nfc_jni_get_monitor()->concurrency_mutex) +#define CONCURRENCY_UNLOCK() pthread_mutex_unlock(&nfc_jni_get_monitor()->concurrency_mutex) + +namespace android { + +extern JavaVM *vm; + +JNIEnv *nfc_get_env(); + +bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext); +void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData); +void nfc_cb_data_releaseAll(); + +const char* nfc_jni_get_status_name(NFCSTATUS status); +int nfc_jni_cache_object(JNIEnv *e, const char *clsname, + jobject *cached_obj); +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o); +struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e); +nfc_jni_native_monitor_t* nfc_jni_init_monitor(void); +nfc_jni_native_monitor_t* nfc_jni_get_monitor(void); + +int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak); +void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, + uint8_t count, jintArray* techList, jintArray* handleList, + jintArray* typeList); + +/* P2P */ +phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o); +jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o); + +/* TAG */ +jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o); +jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o); +phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o); +jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o); + +/* LLCP */ +phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o); + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e); +int register_com_android_nfc_NativeNfcTag(JNIEnv *e); +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e); +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e); +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e); +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e); + +} // namespace android + +#endif diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..188edb4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_receive_callback(void* pContext, uint8_t ssap, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_receiveFrom_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + pCallbackData->pContext = (void*)ssap; + TRACE("RECEIVE UI_FRAME FROM SAP %d OK \n", ssap); + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_sendTo_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* +* Methods +*/ +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo(JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_SendTo()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SendTo(hRemoteDevice, + hLlcpSocket, + nsap, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_SendTo() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jobject com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv *e, jobject o, jint linkMiu) +{ + NFCSTATUS ret; + struct timespec ts; + uint8_t ssap; + jobject llcpPacket = NULL; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer; + jclass clsLlcpPacket; + jfieldID f; + jbyteArray receivedData = NULL; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create new LlcpPacket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/LlcpPacket",&(llcpPacket)) == -1) + { + ALOGE("Find LlcpPacket class error"); + goto clean_and_return; + } + + /* Get NativeConnectionless class object */ + clsLlcpPacket = e->GetObjectClass(llcpPacket); + if(e->ExceptionCheck()) + { + ALOGE("Get Object class error"); + goto clean_and_return; + } + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + TRACE("phLibNfc_Llcp_RecvFrom(), Socket Handle = 0x%02x, Link LIU = %d", hLlcpSocket, linkMiu); + + sReceiveBuffer.buffer = (uint8_t*)malloc(linkMiu); + sReceiveBuffer.length = linkMiu; + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_RecvFrom(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + &cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_RecvFrom() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ssap = (uint32_t)cb_data.pContext; + TRACE("Data Received From SSAP = %d\n, length = %d", ssap, sReceiveBuffer.length); + + /* Set Llcp Packet remote SAP */ + f = e->GetFieldID(clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField(llcpPacket, f,(jbyte)ssap); + + /* Set Llcp Packet Buffer */ + ALOGD("Set LlcpPacket Data Buffer\n"); + f = e->GetFieldID(clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray(sReceiveBuffer.length); + e->SetByteArrayRegion(receivedData, 0, sReceiveBuffer.length,(jbyte *)sReceiveBuffer.buffer); + e->SetObjectField(llcpPacket, f, receivedData); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return llcpPacket; +} + +static jboolean com_android_nfc_NativeLlcpConnectionlessSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + TRACE("Close Connectionless socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doSendTo}, + + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doReceiveFrom}, + + {"doClose", "()Z", (void *)com_android_nfc_NativeLlcpConnectionlessSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + gMethods, NELEM(gMethods)); +} + +} // android namespace diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..92de3e4 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode); +/* + * Callbacks + */ +static void nfc_jni_llcp_accept_socket_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +/* + * Utils + */ + +static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor, + phLibNfc_Handle hServerSocket) +{ + nfc_jni_listen_data_t * pListenData; + phLibNfc_Handle pIncomingSocket = NULL; + + /* Look for a pending incoming connection on the current server */ + LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries) + { + if (pListenData->pServerSocket == hServerSocket) + { + pIncomingSocket = pListenData->pIncomingSocket; + LIST_REMOVE(pListenData, entries); + free(pListenData); + break; + } + } + + return pIncomingSocket; +} + +/* + * Methods + */ +static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret = NFCSTATUS_SUCCESS; + struct timespec ts; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + jfieldID f; + jclass clsNativeLlcpSocket; + jobject clientSocket = NULL; + struct nfc_jni_callback_data cb_data; + phLibNfc_Handle hIncomingSocket, hServerSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Get server socket */ + hServerSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Set socket options with the socket options of the service */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength); + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + + while(cb_data.status != NFCSTATUS_SUCCESS) + { + /* Wait for tag Notification */ + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) { + pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex); + } + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + /* Accept the incomming socket */ + TRACE("phLibNfc_Llcp_Accept()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Accept( hIncomingSocket, + &sOptions, + &sWorkingBuffer, + nfc_jni_llcp_transport_socket_err_callback, + nfc_jni_llcp_accept_socket_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + // NOTE: This may happen if link went down since incoming socket detected, then + // just drop it and start a new accept loop. + ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + continue; + } + TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + /* NOTE: Do not generate an error if the accept failed to avoid error in server application */ + ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status)); + } + } + + /* Create new LlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGD("LLCP Socket creation error"); + goto clean_and_return; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGD("LLCP Socket get class object error"); + goto clean_and_return; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hIncomingSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + + TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return clientSocket; +} + +static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor(); + + TRACE("Close Service socket"); + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + /* TODO: implement accept abort */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); + + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("Close Service socket OK"); + return TRUE; + } + else + { + ALOGD("Close Service socket KO"); + return FALSE; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_NativeLlcpServiceSocket_doAccept}, + + {"doClose", "()Z", + (void *)com_NativeLlcpServiceSocket_doClose}, +}; + + +int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpServiceSocket", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp new file mode 100644 index 0000000..0c0b830 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +namespace android { + +/* + * Callbacks + */ + +static void nfc_jni_disconnect_callback(void* pContext, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + +static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + TRACE("Socket connected\n"); + } + else + { + ALOGD("Socket not connected:"); + switch(nErrCode) + { + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE: + { + ALOGD("> SAP NOT ACTIVE\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND: + { + ALOGD("> SAP NOT FOUND\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED: + { + ALOGD("> CONNECT REJECTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED: + { + ALOGD("> CONNECT NOT ACCEPTED\n"); + }break; + + case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE: + { + ALOGD("> SOCKET NOT AVAILABLE\n"); + }break; + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + + + + +static void nfc_jni_receive_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_receive_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcp_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Methods + */ +static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_Llcp_Connect(%d)",nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Connect(hRemoteDevice, + hLlcpSocket, + nSap, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("LLCP Connect request failed"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn) +{ + NFCSTATUS ret; + struct timespec ts; + phNfc_sData_t serviceName = {0}; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Service socket */ + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + + TRACE("phLibNfc_Llcp_ConnectByUri()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice, + hLlcpSocket, + &serviceName, + nfc_jni_connect_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + + /* Retrieve socket handle */ + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_Close()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return FALSE; + } + TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return TRUE; +} + +static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray data) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sSendBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jboolean result = JNI_FALSE; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL); + sSendBuffer.length = (uint32_t)e->GetArrayLength(data); + + TRACE("phLibNfc_Llcp_Send()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Send(hRemoteDevice, + hLlcpSocket, + &sSendBuffer, + nfc_jni_send_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (sSendBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray buffer) +{ + NFCSTATUS ret; + struct timespec ts; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phNfc_sData_t sReceiveBuffer = {NULL, 0}; + struct nfc_jni_callback_data cb_data; + jint result = -1; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL); + sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer); + + TRACE("phLibNfc_Llcp_Recv()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Recv(hRemoteDevice, + hLlcpSocket, + &sReceiveBuffer, + nfc_jni_receive_callback, + (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_PENDING) + { + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + } + else if (ret == NFCSTATUS_SUCCESS) + { + result = sReceiveBuffer.length; + } + else + { + /* Return status should be either SUCCESS or PENDING */ + ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + +clean_and_return: + if (sReceiveBuffer.buffer != NULL) + { + e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.miu; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + +static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + phLibNfc_Handle hRemoteDevice; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t remoteSocketOption; + + /* Retrieve handles */ + hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o); + hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o); + + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice, + hLlcpSocket, + &remoteSocketOption); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return remoteSocketOption.rw; + } + else + { + ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return 0; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnect}, + + {"doConnectBy", "(Ljava/lang/String;)Z", + (void *)com_android_nfc_NativeLlcpSocket_doConnectBy}, + + {"doClose", "()Z", + (void *)com_android_nfc_NativeLlcpSocket_doClose}, + + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeLlcpSocket_doSend}, + + {"doReceive", "([B)I", + (void *)com_android_nfc_NativeLlcpSocket_doReceive}, + + {"doGetRemoteSocketMiu", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU}, + + {"doGetRemoteSocketRw", "()I", + (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp new file mode 100644 index 0000000..704ee6a --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -0,0 +1,2622 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "com_android_nfc.h" + +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + +extern uint32_t libnfc_llc_error_count; + +static phLibNfc_sConfig_t gDrvCfg; +void *gHWRef; +static phNfc_sData_t gInputParam; +static phNfc_sData_t gOutputParam; + +uint8_t device_connected_flag; +static bool driverConfigured = FALSE; + +static phLibNfc_Handle hLlcpHandle; +static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; +static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; + +static jmethodID cached_NfcManager_notifyNdefMessageListeners; +static jmethodID cached_NfcManager_notifyTransactionListeners; +static jmethodID cached_NfcManager_notifyLlcpLinkActivation; +static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; +static jmethodID cached_NfcManager_notifyTargetDeselected; + +static jmethodID cached_NfcManager_notifySeFieldActivated; +static jmethodID cached_NfcManager_notifySeFieldDeactivated; + +static jmethodID cached_NfcManager_notifySeApduReceived; +static jmethodID cached_NfcManager_notifySeMifareAccess; +static jmethodID cached_NfcManager_notifySeEmvCardRemoval; + +namespace android { + +phLibNfc_Handle storedHandle = 0; + +struct nfc_jni_native_data *exported_nat = NULL; + +/* Internal functions declaration */ +static void *nfc_jni_client_thread(void *arg); +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_se_set_mode_callback(void *context, + phLibNfc_Handle handle, NFCSTATUS status); +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume); +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status); +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status); +static bool performDownload(struct nfc_jni_native_data *nat, bool takeLock); + +/* + * Deferred callback called when client thread must be exited + */ +static void client_kill_deferred_call(void* arg) +{ + struct nfc_jni_native_data *nat = (struct nfc_jni_native_data *)arg; + + nat->running = FALSE; +} + +static void kill_client(nfc_jni_native_data *nat) +{ + phDal4Nfc_Message_Wrapper_t wrapper; + phLibNfc_DeferredCall_t *pMsg; + + usleep(50000); + + ALOGD("Terminating client thread..."); + + pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); + pMsg->pCallback = client_kill_deferred_call; + pMsg->pParameter = (void*)nat; + + wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + wrapper.msg.pMsgData = pMsg; + wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); + + phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); +} + +static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_ioctl_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_deinit_download_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static int nfc_jni_download_locked(struct nfc_jni_native_data *nat, uint8_t update) +{ + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + struct timespec ts; + NFCSTATUS status = NFCSTATUS_FAILED; + phLibNfc_StackCapabilities_t caps; + struct nfc_jni_callback_data cb_data; + bool result; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + if(update) + { + //deinit + TRACE("phLibNfc_Mgt_DeInitialize() (download)"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts)) + { + ALOGW("Deinitialization timed out (download)"); + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGW("Deinitialization FAILED (download)"); + } + TRACE("Deinitialization SUCCESS (download)"); + } + + result = performDownload(nat, false); + + if (!result) { + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + status = cb_data.status; + goto clean_and_return; + } + + /* ====== CAPABILITIES ======= */ + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /*Download is successful*/ + status = NFCSTATUS_SUCCESS; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + return status; +} + +static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat) +{ + char value[PROPERTY_VALUE_MAX]; + int result = FALSE; + NFCSTATUS status; + + /* ====== CONFIGURE DRIVER ======= */ + /* Configure hardware link */ + gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); + + TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x)", gDrvCfg.nClientId); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); + REENTRANCE_UNLOCK(); + if(status == NFCSTATUS_ALREADY_INITIALISED) { + ALOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) + { + ALOGE("pthread_create failed"); + goto clean_and_return; + } + + driverConfigured = TRUE; + +clean_and_return: + return result; +} + +static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat) +{ + int result = FALSE; + NFCSTATUS status; + + /* Unconfigure driver */ + TRACE("phLibNfc_Mgt_UnConfigureDriver()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status)); + } + else + { + ALOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = TRUE; + } + + driverConfigured = FALSE; + + return result; +} + +/* Initialization function */ +static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { + struct timespec ts; + uint8_t resp[16]; + NFCSTATUS status; + phLibNfc_StackCapabilities_t caps; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; + phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; + struct nfc_jni_callback_data cb_data; + uint8_t firmware_status; + uint8_t update = TRUE; + int result = JNI_FALSE; + const hw_module_t* hw_module; + nfc_pn544_device_t* pn544_dev = NULL; + int ret = 0; + ALOGD("Start Initialization\n"); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Get EEPROM values and device port from product-specific settings */ + ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module); + if (ret) { + ALOGE("hw_get_module() failed."); + goto clean_and_return; + } + ret = nfc_pn544_open(hw_module, &pn544_dev); + if (ret) { + ALOGE("Could not open pn544 hw_module."); + goto clean_and_return; + } + if (pn544_dev->num_eeprom_settings == 0 || pn544_dev->eeprom_settings == NULL) { + ALOGE("Could not load EEPROM settings"); + goto clean_and_return; + } + + /* Reset device connected handle */ + device_connected_flag = 0; + + /* Reset stored handle */ + storedHandle = 0; + + /* Initialize Driver */ + if(!driverConfigured) + { + nfc_jni_configure_driver(nat); + } + + /* ====== INITIALIZE ======= */ + + TRACE("phLibNfc_Mgt_Initialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + update = FALSE; + goto force_download; + } + TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + update = FALSE; + goto force_download; + } + + /* ====== CAPABILITIES ======= */ + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + } + else + { + ALOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", + caps.psDevCapabilities.hal_version, + caps.psDevCapabilities.fw_version, + caps.psDevCapabilities.hw_version, + caps.psDevCapabilities.model_id, + caps.psDevCapabilities.hci_version, + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], + caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], + caps.psDevCapabilities.firmware_update_info); + } + + /* ====== FIRMWARE VERSION ======= */ + if(caps.psDevCapabilities.firmware_update_info) + { +force_download: + for (i=0; i<3; i++) + { + TRACE("Firmware version not UpToDate"); + status = nfc_jni_download_locked(nat, update); + if(status == NFCSTATUS_SUCCESS) + { + ALOGI("Firmware update SUCCESS"); + break; + } + ALOGW("Firmware update FAILED"); + update = FALSE; + } + if(i>=3) + { + ALOGE("Unable to update firmware, giving up"); + goto clean_and_return; + } + } + else + { + TRACE("Firmware version UpToDate"); + } + /* ====== EEPROM SETTINGS ======= */ + + // Update EEPROM settings + TRACE("****** START EEPROM SETTINGS UPDATE ******"); + for (i = 0; i < pn544_dev->num_eeprom_settings; i++) + { + char eeprom_property[PROPERTY_KEY_MAX]; + char eeprom_value[PROPERTY_VALUE_MAX]; + uint8_t* eeprom_base = &(pn544_dev->eeprom_settings[i*4]); + TRACE("> EEPROM SETTING: %d", i); + + // Check for override of this EEPROM value in properties + snprintf(eeprom_property, sizeof(eeprom_property), "debug.nfc.eeprom.%02X%02X", + eeprom_base[1], eeprom_base[2]); + TRACE(">> Checking property: %s", eeprom_property); + if (property_get(eeprom_property, eeprom_value, "") == 2) { + int eeprom_value_num = (int)strtol(eeprom_value, (char**)NULL, 16); + ALOGD(">> Override EEPROM addr 0x%02X%02X with value %02X", + eeprom_base[1], eeprom_base[2], eeprom_value_num); + eeprom_base[3] = eeprom_value_num; + } + + TRACE(">> Addr: 0x%02X%02X set to: 0x%02X", eeprom_base[1], eeprom_base[2], + eeprom_base[3]); + gInputParam.buffer = eeprom_base; + gInputParam.length = 0x04; + gOutputParam.buffer = resp; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Initialization Status */ + if (cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + } + TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); + + /* ====== SECURE ELEMENTS ======= */ + + REENTRANCE_LOCK(); + ALOGD("phLibNfc_SE_GetSecureElementList()"); + status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + + ALOGD("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i < No_SE; i++) + { + if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); + } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); + } + + /* Set SE mode - Off */ + REENTRANCE_LOCK(); + status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, + phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + } + + /* ====== LLCP ======= */ + + /* LLCP Params */ + TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); + LlcpConfigInfo.miu = nat->miu; + LlcpConfigInfo.lto = nat->lto; + LlcpConfigInfo.wks = nat->wks; + LlcpConfigInfo.option = nat->opt; + + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, + nfc_jni_llcpcfg_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, + nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* ===== DISCOVERY ==== */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.Duration = 300000; /* in ms */ + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Register for the card emulation mode */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("phLibNfc_SE_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); + + + /* ====== END ======= */ + + ALOGI("NFC Initialized"); + + result = TRUE; + +clean_and_return: + if (result != TRUE) + { + if(nat) + { + kill_client(nat); + } + } + if (pn544_dev != NULL) { + nfc_pn544_close(pn544_dev); + } + nfc_cb_data_deinit(&cb_data); + + return result; +} + +static int is_user_build() { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", value, ""); + return !strncmp("user", value, PROPERTY_VALUE_MAX); +} + +/* + * Last-chance fallback when there is no clean way to recover + * Performs a software reset + */ +void emergency_recovery(struct nfc_jni_native_data *nat) { + if (!is_user_build()) { + ALOGE("emergency_recovery: force restart of NFC service"); + } else { + // dont recover immediately, so we can debug + unsigned int t; + for (t=1; t < 1000000; t <<= 1) { + ALOGE("emergency_recovery: NFC stack dead-locked"); + sleep(t); + } + } + phLibNfc_Mgt_Recovery(); + abort(); // force a noisy crash +} + +void nfc_jni_reset_timeout_values() +{ + REENTRANCE_LOCK(); + phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); + phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); + phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); + phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); + REENTRANCE_UNLOCK(); +} + +/* + * Restart the polling loop when unable to perform disconnect + */ +void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) +{ + nfc_jni_start_discovery_locked(nat, true); +} + + /* + * Utility to recover UID from target infos + */ +static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + phNfc_sData_t uid; + + switch(psRemoteDevInfo->RemDevType) + { + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_3A_PICC: + case phNfc_eMifare_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; + break; + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; + uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); + break; + case phNfc_eFelica_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; + uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; + break; + case phNfc_eJewel_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; + break; + case phNfc_eISO15693_PICC: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; + uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; + break; + case phNfc_eNfcIP1_Target: + case phNfc_eNfcIP1_Initiator: + uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; + uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; + break; + default: + uid.buffer = NULL; + uid.length = 0; + break; + } + + return uid; +} + +/* + * NFC stack message processing + */ +static void *nfc_jni_client_thread(void *arg) +{ + struct nfc_jni_native_data *nat; + JNIEnv *e; + JavaVMAttachArgs thread_args; + phDal4Nfc_Message_Wrapper_t wrapper; + + nat = (struct nfc_jni_native_data *)arg; + + thread_args.name = "NFC Message Loop"; + thread_args.version = nat->env_version; + thread_args.group = NULL; + + nat->vm->AttachCurrentThread(&e, &thread_args); + pthread_setname_np(pthread_self(), "message"); + + TRACE("NFC client started"); + nat->running = TRUE; + while(nat->running == TRUE) + { + /* Fetch next message from the NFC stack message queue */ + if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, + sizeof(phLibNfc_Message_t), 0, 0) == -1) + { + ALOGE("NFC client received bad message"); + continue; + } + + switch(wrapper.msg.eMsgType) + { + case PH_LIBNFC_DEFERREDCALL_MSG: + { + phLibNfc_DeferredCall_t *msg = + (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); + + REENTRANCE_LOCK(); + msg->pCallback(msg->pParameter); + REENTRANCE_UNLOCK(); + + break; + } + } + } + TRACE("NFC client stopped"); + + nat->vm->DetachCurrentThread(); + + return NULL; +} + +extern uint8_t nfc_jni_is_ndef; +extern uint8_t *nfc_jni_ndef_buf; +extern uint32_t nfc_jni_ndef_buf_len; + +static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = +{ + 3, + { 0x46, 0x66, 0x6D } +}; + +/* + * Callbacks + */ + +/* P2P - LLCP callbacks */ +static void nfc_jni_llcp_linkStatus_callback(void *pContext, + phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) +{ + phFriNfc_Llcp_sLinkParameters_t sLinkParams; + JNIEnv *e; + NFCSTATUS status; + + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; + + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + /* Update link status */ + g_eLinkStatus = eLinkStatus; + + if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) + { + REENTRANCE_LOCK(); + status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_SUCCESS) + { + ALOGW("GetRemote Info failded - Status = %02x",status); + } + else + { + ALOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, + sLinkParams.miu, + sLinkParams.option, + sLinkParams.wks); + device_connected_flag = 1; + } + } + else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) + { + ALOGI("LLCP Link deactivated"); + free(pContextData); + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Reset incoming socket list */ + while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) + { + pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); + LIST_REMOVE(pListenData, entries); + free(pListenData); + } + + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } +} + +static void nfc_jni_checkLlcp_callback(void *context, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; + + LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, + phLibNfc_Handle hIncomingSocket) +{ + phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; + nfc_jni_listen_data_t * pListenData = NULL; + nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); + + TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); + + pthread_mutex_lock(&pMonitor->incoming_socket_mutex); + + /* Store the connection request */ + pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); + if (pListenData == NULL) + { + ALOGE("Failed to create structure to handle incoming LLCP connection request"); + goto clean_and_return; + } + pListenData->pServerSocket = hServiceSocket; + pListenData->pIncomingSocket = hIncomingSocket; + LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); + + /* Signal pending accept operations that the list is updated */ + pthread_cond_broadcast(&pMonitor->incoming_socket_cond); + +clean_and_return: + pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); +} + +void nfc_jni_llcp_transport_socket_err_callback(void* pContext, + uint8_t nErrCode) +{ + PHNFC_UNUSED_VARIABLE(pContext); + + TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); + + if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) + { + ALOGW("Frame Rejected - Disconnected"); + } + else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) + { + ALOGD("Socket Disconnected"); + } +} + + +static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_discover_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static uint8_t find_preferred_target(phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNoOfRemoteDev) +{ + // Always prefer p2p targets over other targets. Otherwise, select the first target + // reported. + uint8_t preferred_index = 0; + for (uint8_t i = 0; i < uNoOfRemoteDev; i++) { + if((psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { + preferred_index = i; + } + } + return preferred_index; +} + +static void nfc_jni_Discovery_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, NFCSTATUS status) +{ + JNIEnv *e; + NFCSTATUS ret; + jclass tag_cls = NULL; + jobject target_array; + jobject tag; + jmethodID ctor; + jfieldID f; + const char * typeName; + jbyteArray tagUid; + jbyteArray generalBytes = NULL; + struct nfc_jni_native_data *nat; + struct timespec ts; + phNfc_sData_t data; + int i; + int target_index = 0; // Target that will be reported (if multiple can be >0) + + nat = (struct nfc_jni_native_data *)pContext; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); + + /* Notify manager that a target was deselected */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); + TRACE("Discovered %d tags", uNofRemoteDev); + + target_index = find_preferred_target(psRemoteDevList, uNofRemoteDev); + + /* Reset device connected flag */ + device_connected_flag = 1; + phLibNfc_sRemoteDevInformation_t *remDevInfo = psRemoteDevList[target_index].psRemoteDevInfo; + phLibNfc_Handle remDevHandle = psRemoteDevList[target_index].hTargetDev; + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + + tag_cls = e->GetObjectClass(nat->cached_P2pDevice); + if(e->ExceptionCheck()) + { + ALOGE("Get Object Class Error"); + kill_client(nat); + return; + } + + /* New target instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID(tag_cls, "mMode", "I"); + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + ALOGD("Discovered P2P Initiator"); + e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); + } + else + { + ALOGD("Discovered P2P Target"); + e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); + } + + if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + { + /* Set General Bytes */ + f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes length ="); + for(i=0;iRemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) + { + ALOGD("%02x ", remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); + } + + generalBytes = e->NewByteArray(remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + + e->SetByteArrayRegion(generalBytes, 0, + remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, + (jbyte *)remDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); + + e->SetObjectField(tag, f, generalBytes); + } + + /* Set tag handle */ + f = e->GetFieldID(tag_cls, "mHandle", "I"); + e->SetIntField(tag, f,(jint)remDevHandle); + TRACE("Target handle = 0x%08x",remDevHandle); + } + else + { + tag_cls = e->GetObjectClass(nat->cached_NfcTag); + if(e->ExceptionCheck()) + { + kill_client(nat); + return; + } + + /* New tag instance */ + ctor = e->GetMethodID(tag_cls, "", "()V"); + tag = e->NewObject(tag_cls, ctor); + + bool multi_protocol = false; + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + TRACE("Multiple Protocol TAG detected\n"); + multi_protocol = true; + } + + /* Set tag UID */ + f = e->GetFieldID(tag_cls, "mUid", "[B"); + data = get_target_uid(remDevInfo); + tagUid = e->NewByteArray(data.length); + if(data.length > 0) + { + e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); + } + e->SetObjectField(tag, f, tagUid); + + /* Generate technology list */ + jintArray techList; + jintArray handleList; + jintArray typeList; + nfc_jni_get_technology_tree(e, psRemoteDevList, + multi_protocol ? uNofRemoteDev : 1, + &techList, &handleList, &typeList); + + /* Push the technology list into the java object */ + f = e->GetFieldID(tag_cls, "mTechList", "[I"); + e->SetObjectField(tag, f, techList); + + f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); + e->SetObjectField(tag, f, handleList); + + f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField(tag, f, typeList); + + f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); + e->SetIntField(tag, f,(jint)-1); + + f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); + e->SetIntField(tag, f,(jint)-1); + } + + storedHandle = remDevHandle; + if (nat->tag != NULL) { + e->DeleteGlobalRef(nat->tag); + } + nat->tag = e->NewGlobalRef(tag); + + /* Notify the service */ + TRACE("Notify Nfc Service"); + if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) + || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target)) + { + /* Store the hanlde of the P2P device */ + hLlcpHandle = remDevHandle; + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + else + { + /* Notify manager that new a tag was found */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); + if(e->ExceptionCheck()) + { + ALOGE("Exception occured"); + kill_client(nat); + } + } + e->DeleteLocalRef(tag); + } +} + +static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_init_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_deinit_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Card Emulation callback */ +static void nfc_jni_transaction_callback(void *context, + phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, + phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) +{ + JNIEnv *e; + jobject tmp_array = NULL; + jobject mifare_block = NULL; + struct nfc_jni_native_data *nat; + phNfc_sData_t *aid; + phNfc_sData_t *mifare_command; + struct nfc_jni_callback_data *pCallbackData; + int i=0; + + LOG_CALLBACK("nfc_jni_transaction_callback", status); + + nat = (struct nfc_jni_native_data *)context; + + nat->vm->GetEnv( (void **)&e, nat->env_version); + + if(status == NFCSTATUS_SUCCESS) + { + switch(evt_type) + { + case phLibNfc_eSE_EvtStartTransaction: + { + TRACE("> SE EVT_START_TRANSACTION"); + if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) + { + aid = &(evt_info->UiccEvtInfo.aid); + + ALOGD("> AID DETECTED"); + + if(aid != NULL) + { + char aid_str[AID_MAXLEN * 2 + 1]; + aid_str[0] = '\0'; + for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { + snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); + } + ALOGD("> AID: %s", aid_str); + + tmp_array = e->NewByteArray(aid->length); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + goto error; + } + + TRACE("Notify Nfc Service"); + /* Notify manager that a new event occurred on a SE */ + e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); + if(e->ExceptionCheck()) + { + goto error; + } + } + else + { + ALOGD("> NO AID DETECTED"); + } + }break; + + case phLibNfc_eSE_EvtApduReceived: + { + phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); + TRACE("> SE EVT_APDU_RECEIVED"); + + if (apdu != NULL) { + TRACE(" APDU length=%d", apdu->length); + tmp_array = e->NewByteArray(apdu->length); + if (tmp_array == NULL) { + goto error; + } + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); + if (e->ExceptionCheck()) { + goto error; + } + } else { + TRACE(" APDU EMPTY"); + } + + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); + }break; + + case phLibNfc_eSE_EvtCardRemoval: + { + TRACE("> SE EVT_EMV_CARD_REMOVAL"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); + }break; + + case phLibNfc_eSE_EvtMifareAccess: + { + TRACE("> SE EVT_MIFARE_ACCESS"); + mifare_command = &(evt_info->UiccEvtInfo.aid); + TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); + tmp_array = e->NewByteArray(2); + if (tmp_array == NULL) + { + goto error; + } + + e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); + if(e->ExceptionCheck()) + { + goto error; + } + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); + }break; + + case phLibNfc_eSE_EvtFieldOn: + { + TRACE("> SE EVT_FIELD_ON"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); + }break; + + case phLibNfc_eSE_EvtFieldOff: + { + TRACE("> SE EVT_FIELD_OFF"); + TRACE("Notify Nfc Service"); + e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); + }break; + + default: + { + TRACE("Unknown SE event"); + }break; + } + } + else + { + ALOGE("SE transaction notification error"); + goto error; + } + + /* Function finished, now clean and return */ + goto clean_and_return; + + error: + /* In case of error, just discard the notification */ + ALOGE("Failed to send SE transaction notification"); + e->ExceptionClear(); + + clean_and_return: + if(tmp_array != NULL) + { + e->DeleteLocalRef(tmp_array); + } +} + +static void nfc_jni_se_set_mode_callback(void *pContext, + phLibNfc_Handle handle, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* + * NFCManager methods + */ + +static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume) +{ + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ + nfc_jni_reset_timeout_values(); + + /* Reload the p2p modes */ + nat->discovery_cfg.NfcIP_Mode = nat->p2p_initiator_modes; //initiator + nat->discovery_cfg.NfcIP_Target_Mode = nat->p2p_target_modes; //target + nat->discovery_cfg.NfcIP_Tgt_Disable = FALSE; + + /* Reset device connected flag */ + device_connected_flag = 0; + + /* Start Polling loop */ + TRACE("****** Start NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG, + nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + +static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) +{ + phLibNfc_sADD_Cfg_t discovery_cfg; + NFCSTATUS ret; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + discovery_cfg.PollDevInfo.PollEnabled = 0; + discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; + discovery_cfg.NfcIP_Target_Mode = 0; + discovery_cfg.NfcIP_Tgt_Disable = TRUE; + + /* Start Polling loop */ + TRACE("****** Stop NFC Discovery ******"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", + discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", + discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", + discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); + + if(ret != NFCSTATUS_PENDING) + { + emergency_recovery(nat); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); +} + + +static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nfc_jni_stop_discovery_locked(nat); + + CONCURRENCY_UNLOCK(); + +} + +static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + + CONCURRENCY_LOCK(); + + nat = nfc_jni_get_nat(e, o); + + /* Register callback for remote device notifications. + * Must re-register every time we turn on discovery, since other operations + * (such as opening the Secure Element) can change the remote device + * notification callback*/ + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", + nat->registry_info.Jewel==TRUE?"J":"", + nat->registry_info.MifareUL==TRUE?"UL":"", + nat->registry_info.MifareStd==TRUE?"Mi":"", + nat->registry_info.Felica==TRUE?"F":"", + nat->registry_info.ISO14443_4A==TRUE?"4A":"", + nat->registry_info.ISO14443_4B==TRUE?"4B":"", + nat->registry_info.NFC==TRUE?"P2P":"", + nat->registry_info.ISO15693==TRUE?"R":"", ret); + + nfc_jni_start_discovery_locked(nat, false); +clean_and_return: + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { + CONCURRENCY_LOCK(); + nfc_jni_reset_timeout_values(); + CONCURRENCY_UNLOCK(); +} + +static void setFelicaTimeout(jint timeout) { + // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. + // It can be set to 0 to disable the timeout altogether, in which case we + // use the sw watchdog as a fallback. + if (timeout <= 255) { + phLibNfc_SetFelicaTimeout(timeout); + } else { + // Disable hw timeout, use sw watchdog for timeout + phLibNfc_SetFelicaTimeout(0); + phLibNfc_SetHciTimeout(timeout); + } + +} +// Calculates ceiling log2 of value +static unsigned int log2(int value) { + unsigned int ret = 0; + bool isPowerOf2 = ((value & (value - 1)) == 0); + while ( (value >> ret) > 1 ) ret++; + if (!isPowerOf2) ret++; + return ret; +} + +// The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X +// spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X +// +// We keep the constant part of the formula in a static; note the factor +// 1000 off, which is due to the fact that the formula calculates seconds, +// but this method gets milliseconds as an argument. +static double nxp_nfc_timeout_factor = (256 * 16) / 13560.0; + +static int calcTimeout(int timeout_in_ms) { + // timeout = (256 * 16 / 13560000) * 2 ^ X + // First find the first X for which timeout > requested timeout + return (log2(ceil(((double) timeout_in_ms) / nxp_nfc_timeout_factor))); +} + +static void setIsoDepTimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + // Then re-compute the actual timeout based on X + double actual_timeout = nxp_nfc_timeout_factor * (1 << value); + // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, + // but it will take some time to get back through the sw layers. + // 500 ms should be enough). + phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); + value |= 0x10; // bit 4 to enable timeout + phLibNfc_SetIsoXchgTimeout(value); + } + else { + // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout + // must be disabled completely, to prevent the PN544 from aborting + // the transaction. We reuse the HCI sw watchdog to catch the timeout + // in that case. + phLibNfc_SetIsoXchgTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static void setNfcATimeout(jint timeout) { + if (timeout <= 4900) { + int value = calcTimeout(timeout); + phLibNfc_SetMifareRawTimeout(value); + } + else { + // Disable mifare raw timeout, use HCI sw watchdog instead + phLibNfc_SetMifareRawTimeout(0x00); + phLibNfc_SetHciTimeout(timeout); + } +} + +static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, + jint tech, jint timeout) { + bool success = false; + CONCURRENCY_LOCK(); + if (timeout <= 0) { + ALOGE("Timeout must be positive."); + return false; + } else { + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + setNfcATimeout(timeout); + success = true; + break; + case TARGET_TYPE_ISO14443_4: + setIsoDepTimeout(timeout); + success = true; + break; + case TARGET_TYPE_FELICA: + setFelicaTimeout(timeout); + success = true; + break; + default: + ALOGW("doSetTimeout: Timeout not supported for tech %d", tech); + success = false; + } + } + CONCURRENCY_UNLOCK(); + return success; +} + +static jint com_android_nfc_NfcManager_doGetTimeout( JNIEnv *e, jobject o, + jint tech) { + int timeout = -1; + CONCURRENCY_LOCK(); + switch (tech) { + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + // Intentional fall-through, Mifare UL, Classic + // transceive just uses raw 3A frames + case TARGET_TYPE_ISO14443_3A: + timeout = phLibNfc_GetMifareRawTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_ISO14443_4: + timeout = phLibNfc_GetIsoXchgTimeout() & 0x0F; // lower 4 bits only + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Timeout returned from libnfc needs conversion to ms + timeout = (nxp_nfc_timeout_factor * (1 << timeout)); + } + break; + case TARGET_TYPE_FELICA: + timeout = phLibNfc_GetFelicaTimeout(); + if (timeout == 0) { + timeout = phLibNfc_GetHciTimeout(); + } else { + // Felica timeout already in ms + } + break; + default: + ALOGW("doGetTimeout: Timeout not supported for tech %d", tech); + break; + } + CONCURRENCY_UNLOCK(); + return timeout; +} + + +static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct nfc_jni_native_data *nat = NULL; + jclass cls; + jobject obj; + jfieldID f; + + TRACE("****** Init Native Structure ******"); + + /* Initialize native structure */ + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if(nat == NULL) + { + ALOGD("malloc of nfc_jni_native_data failed"); + return FALSE; + } + memset(nat, 0, sizeof(*nat)); + e->GetJavaVM(&(nat->vm)); + nat->env_version = e->GetVersion(); + nat->manager = e->NewGlobalRef(o); + + cls = e->GetObjectClass(o); + f = e->GetFieldID(cls, "mNative", "I"); + e->SetIntField(o, f, (jint)nat); + + /* Initialize native cached references */ + cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, + "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + + cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, + "notifyTransactionListeners", "([B)V"); + + cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, + "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + + cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, + "notifyTargetDeselected","()V"); + + cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, + "notifySeFieldActivated", "()V"); + + cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, + "notifySeFieldDeactivated", "()V"); + + cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + { + ALOGD("Native Structure initialization failed"); + return FALSE; + } + TRACE("****** Init Native Structure OK ******"); + return TRUE; + +} + +/* Init/Deinit method */ +static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + int init_result = JNI_FALSE; +#ifdef TNFC_EMULATOR_ONLY + char value[PROPERTY_VALUE_MAX]; +#endif + jboolean result; + + CONCURRENCY_LOCK(); + +#ifdef TNFC_EMULATOR_ONLY + if (!property_get("ro.kernel.qemu", value, 0)) + { + ALOGE("NFC Initialization failed: not running in an emulator\n"); + goto clean_and_return; + } +#endif + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + nat->seId = SMX_SECURE_ELEMENT_ID; + + nat->lto = 150; // LLCP_LTO + nat->miu = 128; // LLCP_MIU + // WKS indicates well-known services; 1 << sap for each supported SAP. + // We support Link mgmt (SAP 0), SDP (SAP 1) and SNEP (SAP 4) + nat->wks = 0x13; // LLCP_WKS + nat->opt = 0; // LLCP_OPT + nat->p2p_initiator_modes = phNfc_eP2P_ALL; + nat->p2p_target_modes = 0x0E; // All passive except 106, active + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; + nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; + + nat->registry_info.MifareUL = TRUE; + nat->registry_info.MifareStd = TRUE; + nat->registry_info.ISO14443_4A = TRUE; + nat->registry_info.ISO14443_4B = TRUE; + nat->registry_info.Jewel = TRUE; + nat->registry_info.Felica = TRUE; + nat->registry_info.NFC = TRUE; + nat->registry_info.ISO15693 = TRUE; + + exported_nat = nat; + + /* Perform the initialization */ + init_result = nfc_jni_initialize(nat); + +clean_and_return: + CONCURRENCY_UNLOCK(); + + /* Convert the result and return */ + return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; +} + +static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) +{ + struct timespec ts; + NFCSTATUS status; + int result = JNI_FALSE; + struct nfc_jni_native_data *nat; + int bStackReset = FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Clear previous configuration */ + memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); + memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); + + /* Create the local semaphore */ + if (nfc_cb_data_init(&cb_data, NULL)) + { + TRACE("phLibNfc_Mgt_DeInitialize()"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (status == NFCSTATUS_PENDING) + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + + /* Wait for callback response */ + if(sem_timedwait(&cb_data.sem, &ts) == -1) + { + ALOGW("Operation timed out"); + bStackReset = TRUE; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Failed to deinit the stack"); + bStackReset = TRUE; + } + } + else + { + TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + bStackReset = TRUE; + } + nfc_cb_data_deinit(&cb_data); + } + else + { + ALOGE("Failed to create semaphore (errno=0x%08x)", errno); + bStackReset = TRUE; + } + + kill_client(nat); + + if(bStackReset == TRUE) + { + /* Complete deinit. failed, try hard restart of NFC */ + ALOGW("Reseting stack..."); + emergency_recovery(nat); + } + + result = nfc_jni_unconfigure_driver(nat); + + TRACE("NFC Deinitialized"); + + CONCURRENCY_UNLOCK(); + + return TRUE; +} + +/* Secure Element methods */ +static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { + NFCSTATUS ret; + jintArray list= NULL; + phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; + + TRACE("****** Get Secure Element List ******"); + + TRACE("phLibNfc_SE_GetSecureElementList()"); + REENTRANCE_LOCK(); + ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_SUCCESS) { + ALOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + return list; + } + TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, + nfc_jni_get_status_name(ret)); + + TRACE("Nb SE: %d", se_count); + list =e->NewIntArray(se_count); + for (i = 0; i < se_count; i++) { + if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { + ALOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { + ALOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); + ALOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); + } + e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); + } + + e->DeleteLocalRef(list); + + return list; +} + +static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Select Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Virtual */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtualVolatile, nfc_jni_se_set_mode_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING) { + ALOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { + NFCSTATUS ret; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) { + goto clean_and_return; + } + + TRACE("****** Deselect Secure Element ******"); + + TRACE("phLibNfc_SE_SetMode()"); + /* Set SE mode - Default */ + REENTRANCE_LOCK(); + ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeDefault, + nfc_jni_se_set_mode_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); + if (ret != NFCSTATUS_PENDING) { + ALOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if (sem_wait(&cb_data.sem)) { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); +} + +/* Llcp methods */ + +static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + bool freeData = false; + jboolean result = JNI_FALSE; + struct nfc_jni_native_data *nat; + struct nfc_jni_callback_data *cb_data; + + + CONCURRENCY_LOCK(); + + /* Memory allocation for cb_data + * This is on the heap because it is used by libnfc + * even after this call has succesfully finished. It is only freed + * upon link closure in nfc_jni_llcp_linkStatus_callback. + */ + cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(cb_data, (void*)nat)) + { + goto clean_and_return; + } + + /* Check LLCP compliancy */ + TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, + nfc_jni_checkLlcp_callback, + nfc_jni_llcp_linkStatus_callback, + (void*)cb_data); + REENTRANCE_UNLOCK(); + /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol + * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ + if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + freeData = true; + goto clean_and_return; + } + TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data->sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data->status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(cb_data); + if (freeData) { + free(cb_data); + } + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Activate(hLlcpHandle); + REENTRANCE_UNLOCK(); + if(ret == NFCSTATUS_SUCCESS) + { + TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_TRUE; + } + else + { + ALOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + return JNI_FALSE; + } +} + + + +static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, + jint nSap, jstring sn) +{ + NFCSTATUS ret; + jobject connectionlessSocket = NULL; + phLibNfc_Handle hLlcpSocket; + struct nfc_jni_native_data *nat; + phNfc_sData_t sWorkingBuffer = {NULL, 0}; + phNfc_sData_t serviceName = {NULL, 0}; + phLibNfc_Llcp_sLinkParameters_t sParams; + jclass clsNativeConnectionlessSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Allocate Working buffer length */ + phLibNfc_Llcp_GetLocalInfo(hLlcpHandle, &sParams); + sWorkingBuffer.length = sParams.miu + 1; // extra byte for SAP + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, + NULL, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + + /* Create new NativeLlcpConnectionlessSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + { + goto error; + } + + /* Get NativeConnectionless class object */ + clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); + if(e->ExceptionCheck()) + { + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); + e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); + TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); + + /* Set the miu link of the connectionless socket */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); + e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); + TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); + e->SetIntField(connectionlessSocket, f,(jint)nSap); + TRACE("Connectionless socket SAP = %d\n",nSap); + + return connectionlessSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + + if (sWorkingBuffer.buffer != NULL) { + free(sWorkingBuffer.buffer); + } + + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + phNfc_sData_t serviceName; + struct nfc_jni_native_data *nat; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + goto error; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Service socket */ + if (sn == NULL) { + serviceName.buffer = NULL; + serviceName.length = 0; + } else { + serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); + serviceName.length = (uint32_t)e->GetStringUTFLength(sn); + } + + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, &serviceName); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + ret = phLibNfc_Llcp_Close(hLlcpSocket); + goto error; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Listen( hLlcpSocket, + nfc_jni_llcp_transport_listen_socket_callback, + (void*)hLlcpSocket); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + /* Close created socket */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + goto error; + } + TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpServiceSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + { + ALOGE("Llcp Socket object creation error"); + goto error; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); + if(e->ExceptionCheck()) + { + ALOGE("Llcp Socket get object class error"); + goto error; + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); + TRACE("Service socket Handle = %02x\n",hLlcpSocket); + + /* Set socket linear buffer length */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField(serviceSocket, f,(jint)linearBufferLength); + TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField(serviceSocket, f,(jint)miu); + TRACE("Service socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField(serviceSocket, f,(jint)rw); + TRACE("Service socket RW = %d\n",rw); + + return serviceSocket; +error: + if (serviceName.buffer != NULL) { + e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer); + } + return NULL; +} + +static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + NFCSTATUS ret; + phLibNfc_Handle hLlcpSocket; + phLibNfc_Llcp_sSocketOptions_t sOptions; + phNfc_sData_t sWorkingBuffer; + struct nfc_jni_native_data *nat; + jclass clsNativeLlcpSocket; + jfieldID f; + + /* Retrieve native structure address */ + nat = nfc_jni_get_nat(e, o); + + /* Set Connection Oriented socket options */ + sOptions.miu = miu; + sOptions.rw = rw; + + /* Allocate Working buffer length */ + sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; + sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); + + /* Create socket */ + TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, + &sOptions, + &sWorkingBuffer, + &hLlcpSocket, + nfc_jni_llcp_transport_socket_err_callback, + (void*)nat); + REENTRANCE_UNLOCK(); + + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + lastErrorStatus = ret; + return NULL; + } + TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Create new NativeLlcpSocket object */ + if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + { + ALOGE("Llcp socket object creation error"); + return NULL; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass(clientSocket); + if(e->ExceptionCheck()) + { + ALOGE("Get class object error"); + return NULL; + } + + /* Test if an SAP number is present */ + if(nSap != 0) + { + /* Bind socket */ + TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap, NULL); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + lastErrorStatus = ret; + ALOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + /* Close socket created */ + REENTRANCE_LOCK(); + ret = phLibNfc_Llcp_Close(hLlcpSocket); + REENTRANCE_UNLOCK(); + return NULL; + } + TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Set socket SAP */ + f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField(clientSocket, f,(jint)nSap); + TRACE("socket SAP = %d\n",nSap); + } + + /* Set socket handle */ + f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField(clientSocket, f,(jint)hLlcpSocket); + TRACE("socket Handle = %02x\n",hLlcpSocket); + + /* Set socket MIU */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField(clientSocket, f,(jint)miu); + TRACE("socket MIU = %d\n",miu); + + /* Set socket RW */ + f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField(clientSocket, f,(jint)rw); + TRACE("socket RW = %d\n",rw); + + + return clientSocket; +} + +static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) +{ + TRACE("Last Error Status = 0x%02x",lastErrorStatus); + + if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) + { + return ERROR_BUFFER_TOO_SMALL; + } + else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) + { + return ERROR_INSUFFICIENT_RESOURCES; + } + else + { + return lastErrorStatus; + } +} + +static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) +{ + emergency_recovery(NULL); +} + +static void com_android_nfc_NfcManager_doSetP2pInitiatorModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting init modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_initiator_modes = modes; +} + +static void com_android_nfc_NfcManager_doSetP2pTargetModes(JNIEnv *e, jobject o, + jint modes) +{ + ALOGE("Setting target modes to %x", modes); + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + nat->p2p_target_modes = modes; +} + +static bool performDownload(struct nfc_jni_native_data* nat, bool takeLock) { + bool result = FALSE; + int load_result; + bool wasDisabled = FALSE; + uint8_t OutputBuffer[1]; + uint8_t InputBuffer[1]; + NFCSTATUS status = NFCSTATUS_FAILED; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + result = FALSE; + goto clean_and_return; + } + + if (takeLock) + { + CONCURRENCY_LOCK(); + } + + /* Initialize Driver */ + if(!driverConfigured) + { + result = nfc_jni_configure_driver(nat); + wasDisabled = TRUE; + } + TRACE("com_android_nfc_NfcManager_doDownload()"); + + TRACE("Go in Download Mode"); + phLibNfc_Download_Mode(); + + TRACE("Load new Firmware Image"); + load_result = phLibNfc_Load_Firmware_Image(); + if(load_result != 0) + { + TRACE("Load new Firmware Image - status = %d",load_result); + result = FALSE; + goto clean_and_return; + } + + // Download + gInputParam.buffer = InputBuffer; + gInputParam.length = 0x01; + gOutputParam.buffer = OutputBuffer; + gOutputParam.length = 0x01; + + ALOGD("Download new Firmware"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + result = FALSE; + goto clean_and_return; + } + + /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we + try to download an old-style firmware on top of a new-style + firmware. Hence, this is expected behavior, and not an + error condition. */ + if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + result = FALSE; + goto clean_and_return; + } + + if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED) + { + ALOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip."); + } + + /*Download is successful*/ + result = TRUE; +clean_and_return: + TRACE("phLibNfc_HW_Reset()"); + phLibNfc_HW_Reset(); + /* Deinitialize Driver */ + if(wasDisabled) + { + result = nfc_jni_unconfigure_driver(nat); + } + if (takeLock) + { + CONCURRENCY_UNLOCK(); + } + nfc_cb_data_deinit(&cb_data); + return result; +} + +static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o) +{ + struct nfc_jni_native_data *nat = NULL; + nat = nfc_jni_get_nat(e, o); + return performDownload(nat, true); +} + +static jstring com_android_nfc_NfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", libnfc_llc_error_count); + return e->NewStringUTF(buffer); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)com_android_nfc_NfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void *)com_android_nfc_NfcManager_init_native_struc}, + + {"doInitialize", "()Z", + (void *)com_android_nfc_NfcManager_initialize}, + + {"doDeinitialize", "()Z", + (void *)com_android_nfc_NfcManager_deinitialize}, + + {"enableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)com_android_nfc_NfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)com_android_nfc_NfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void *)com_android_nfc_NfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void *)com_android_nfc_NfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)com_android_nfc_NfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)com_android_nfc_NfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)com_android_nfc_NfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)com_android_nfc_NfcManager_doAbort}, + + {"doSetP2pInitiatorModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes","(I)V", + (void *)com_android_nfc_NfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)com_android_nfc_NfcManager_doDump}, +}; + + +int register_com_android_nfc_NativeNfcManager(JNIEnv *e) +{ + nfc_jni_native_monitor_t *nfc_jni_native_monitor; + + nfc_jni_native_monitor = nfc_jni_init_monitor(); + if(nfc_jni_native_monitor == NULL) + { + ALOGE("NFC Manager cannot recover native monitor %x\n", errno); + return -1; + } + + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcManager", + gMethods, NELEM(gMethods)); +} + +} /* namespace android */ diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp new file mode 100755 index 0000000..bf0bffc --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "com_android_nfc.h" + +static phNfc_sData_t *com_android_nfc_jni_transceive_buffer; +static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer; +static phNfc_sRemoteDevInformation_t* SecureElementInfo; +static int secureElementHandle; +extern void *gHWRef; +static int SecureElementTech; +extern uint8_t device_connected_flag; + +namespace android { + +static void com_android_nfc_jni_ioctl_callback ( void* pContext, + phNfc_sData_t* Outparam_Cb, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if (status == NFCSTATUS_SUCCESS ) + { + LOG_CALLBACK("> IOCTL successful",status); + } + else + { + LOG_CALLBACK("> IOCTL error",status); + } + + com_android_nfc_jni_ioctl_buffer = Outparam_Cb; + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status); + + com_android_nfc_jni_transceive_buffer = pResBuffer; + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static void com_android_nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_connect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status); + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +/* Set Secure Element mode callback*/ +static void com_android_nfc_jni_smartMX_setModeCb (void* pContext, + phLibNfc_Handle hSecureElement, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + + if(status==NFCSTATUS_SUCCESS) + { + LOG_CALLBACK("SE Set Mode is Successful",status); + TRACE("SE Handle: %lu", hSecureElement); + } + else + { + LOG_CALLBACK("SE Set Mode is failed\n ",status); + } + + pContextData->status = status; + sem_post(&pContextData->sem); +} + +static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext, + phLibNfc_RemoteDevList_t *psRemoteDevList, + uint8_t uNofRemoteDev, + NFCSTATUS status) +{ + struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; + NFCSTATUS ret; + int i; + JNIEnv *e = nfc_get_env(); + + if(status == NFCSTATUS_DESELECTED) + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status); + } + else + { + LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status); + TRACE("Discovered %d secure elements", uNofRemoteDev); + + if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) + { + bool foundHandle = false; + TRACE("Multiple Protocol supported\n"); + for (i=0; iRemDevType); + if (psRemoteDevList[i].psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC) { + secureElementHandle = psRemoteDevList[i].hTargetDev; + foundHandle = true; + } + } + if (!foundHandle) { + ALOGE("Could not find ISO-DEP secure element"); + status = NFCSTATUS_FAILED; + goto clean_and_return; + } + } + else + { + secureElementHandle = psRemoteDevList->hTargetDev; + } + + TRACE("Secure Element Handle: 0x%08x", secureElementHandle); + + /* Set type name */ + jintArray techList; + nfc_jni_get_technology_tree(e, psRemoteDevList,uNofRemoteDev, &techList, NULL, NULL); + + // TODO: Should use the "connected" technology, for now use the first + if ((techList != NULL) && e->GetArrayLength(techList) > 0) { + e->GetIntArrayRegion(techList, 0, 1, &SecureElementTech); + TRACE("Store Secure Element Info\n"); + SecureElementInfo = psRemoteDevList->psRemoteDevInfo; + + TRACE("Discovered secure element: tech=%d", SecureElementTech); + } + else { + ALOGE("Discovered secure element, but could not resolve tech"); + status = NFCSTATUS_FAILED; + } + + // This thread may not return to the virtual machine for a long time + // so make sure to delete the local refernce to the tech list. + e->DeleteLocalRef(techList); + } + +clean_and_return: + pContextData->status = status; + sem_post(&pContextData->sem); +} + + +static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o) +{ + NFCSTATUS ret; + int semResult; + + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + phLibNfc_sADD_Cfg_t discovery_cfg; + phLibNfc_Registry_Info_t registry_info; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t ExternalRFDetected[3] = {0x00, 0xFC, 0x01}; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + uint8_t Output_Buff[10]; + uint8_t reg_value; + uint8_t mask_value; + struct nfc_jni_callback_data cb_data; + struct nfc_jni_callback_data cb_data_SE_Notification; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data_SE_Notification, NULL)) + { + goto clean_and_return; + } + + /* Registery */ + registry_info.MifareUL = TRUE; + registry_info.MifareStd = TRUE; + registry_info.ISO14443_4A = TRUE; + registry_info.ISO14443_4B = TRUE; + registry_info.Jewel = TRUE; + registry_info.Felica = TRUE; + registry_info.NFC = FALSE; + + CONCURRENCY_LOCK(); + + TRACE("Open Secure Element"); + + /* Check if NFC device is already connected to a tag or P2P peer */ + if (device_connected_flag == 1) + { + ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag"); + goto clean_and_return; + } + + /* Test if External RF field is detected */ + InParam.buffer = ExternalRFDetected; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + /* Check the value */ + reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0]; + mask_value = reg_value & 0x40; + + if(mask_value == 0x40) + { + // There is an external RF field present, fail the open request + ALOGD("Unable to open SE connection, external RF Field detected"); + goto clean_and_return; + } + + /* Get Secure Element List */ + TRACE("phLibNfc_SE_GetSecureElementList()"); + ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE); + if (ret == NFCSTATUS_SUCCESS) + { + TRACE("\n> Number of Secure Element(s) : %d\n", No_SE); + /* Display Secure Element information */ + for (i = 0; i SMX detected"); + TRACE("> Secure Element Handle : %d\n", SE_List[i].hSecureElement); + /* save SMARTMX index */ + SmartMX_detected = 1; + SmartMX_index = i; + } + } + + if(SmartMX_detected) + { + REENTRANCE_LOCK(); + TRACE("phLibNfc_RemoteDev_NtfRegister()"); + ret = phLibNfc_RemoteDev_NtfRegister(®istry_info, + com_android_nfc_jni_open_secure_element_notification_callback, + (void *)&cb_data_SE_Notification); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_SUCCESS) + { + ALOGE("Register Notification error"); + goto clean_and_return; + } + + /* Set wired mode */ + REENTRANCE_LOCK(); + TRACE("phLibNfc_SE_SetMode: Wired mode"); + ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, + phLibNfc_SE_ActModeWired, + com_android_nfc_jni_smartMX_setModeCb, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if (ret != NFCSTATUS_PENDING ) + { + ALOGE("\n> SE Set SmartMX mode ERROR \n" ); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("SE set mode failed"); + goto clean_and_return; + } + + TRACE("Waiting for notification"); + /* Wait for callback response */ + if(sem_wait(&cb_data_SE_Notification.sem)) + { + ALOGE("Secure Element opening error"); + goto clean_and_return; + } + + if(cb_data_SE_Notification.status != NFCSTATUS_SUCCESS && + cb_data_SE_Notification.status != NFCSTATUS_MULTIPLE_PROTOCOLS) + { + ALOGE("SE detection failed"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Connect Tag */ + CONCURRENCY_LOCK(); + TRACE("phLibNfc_RemoteDev_Connect(SMX)"); + REENTRANCE_LOCK(); + ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("CONNECT semaphore error"); + goto clean_and_return; + } + + /* Connect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("Secure Element connect error"); + goto clean_and_return; + } + + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue | 0x40); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(ret!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + /* Return the Handle of the SecureElement */ + return secureElementHandle; + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): No SMX detected"); + goto clean_and_return; + } + } + else + { + ALOGE("phLibNfc_SE_GetSecureElementList(): Error"); + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + nfc_cb_data_deinit(&cb_data_SE_Notification); + + CONCURRENCY_UNLOCK(); + return 0; +} + + +static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle) +{ + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; + uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0; + uint32_t SmartMX_Handle; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t InParam; + phNfc_sData_t OutParam; + uint8_t Output_Buff[10]; + uint8_t GpioGetValue[3] = {0x00, 0xF8, 0x2B}; + uint8_t GpioSetValue[4]; + uint8_t gpioValue; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Close Secure element function "); + + CONCURRENCY_LOCK(); + /* Disconnect */ + TRACE("Disconnecting from SMX (handle = 0x%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, + NFC_SMARTMX_RELEASE, + com_android_nfc_jni_disconnect_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("\n> Disconnect SE ERROR \n" ); + goto clean_and_return; + } + CONCURRENCY_UNLOCK(); + + /* Get GPIO information */ + CONCURRENCY_LOCK(); + InParam.buffer = GpioGetValue; + InParam.length = 3; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Get Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + gpioValue = com_android_nfc_jni_ioctl_buffer->buffer[0]; + TRACE("GpioValue = Ox%02x",gpioValue); + + /* Set GPIO information */ + GpioSetValue[0] = 0x00; + GpioSetValue[1] = 0xF8; + GpioSetValue[2] = 0x2B; + GpioSetValue[3] = (gpioValue & 0xBF); + + TRACE("GpioValue to be set = Ox%02x",GpioSetValue[3]); + + for(i=0;i<4;i++) + { + TRACE("0x%02x",GpioSetValue[i]); + } + + InParam.buffer = GpioSetValue; + InParam.length = 4; + OutParam.buffer = Output_Buff; + TRACE("phLibNfc_Mgt_IoCtl()- GPIO Set Value"); + REENTRANCE_LOCK(); + status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_WRITE,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status!=NFCSTATUS_PENDING) + { + ALOGE("IOCTL status error"); + goto clean_and_return; + } + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("IOCTL semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("READ MEM ERROR"); + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e, + jobject o,jint handle, jbyteArray data) +{ + uint8_t offset = 0; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + + int tech = SecureElementTech; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + TRACE("Exchange APDU function "); + + CONCURRENCY_LOCK(); + + TRACE("Secure Element tech: %d\n", tech); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + /* Prepare transceive info structure */ + if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL) + { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + else if(tech == TARGET_TYPE_ISO14443_4) + { + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + } + + transceive_info.sSendData.buffer = buf + offset; + transceive_info.sSendData.length = buflen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(SMX)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + com_android_nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("TRANSCEIVE semaphore error"); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + ALOGE("TRANSCEIVE error"); + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length); + if(result != NULL) + { + e->SetByteArrayRegion(result, 0, + com_android_nfc_jni_transceive_buffer->length, + (jbyte *)com_android_nfc_jni_transceive_buffer->buffer); + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle) +{ + TRACE("Get Secure element UID function "); + jbyteArray SecureElementUid; + + if(handle == secureElementHandle) + { + SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength); + e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid); + return SecureElementUid; + } + else + { + return NULL; + } +} + +static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle) +{ + jintArray techList; + TRACE("Get Secure element Type function "); + + if(handle == secureElementHandle) + { + techList = e->NewIntArray(1); + e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech); + return techList; + } + else + { + return NULL; + } +} + + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", + (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", + (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect}, + {"doTransceive", "(I[B)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", + (void *)com_android_nfc_NativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", + (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList}, +}; + +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcSecureElement", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp new file mode 100644 index 0000000..dbf8dc9 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -0,0 +1,1255 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" +#include "phNfcHalTypes.h" + +static phLibNfc_Data_t nfc_jni_ndef_rw; +static phLibNfc_Handle handle; +uint8_t *nfc_jni_ndef_buf = NULL; +uint32_t nfc_jni_ndef_buf_len = 0; + +extern uint8_t device_connected_flag; + +namespace android { + +extern phLibNfc_Handle storedHandle; + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); +extern void nfc_jni_reset_timeout_values(); + +/* + * Callbacks + */ + static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_tag_rw_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + if (pCallbackData->pContext != NULL) { + // Store the remote dev info ptr in the callback context + // Note that this ptr will remain valid, it is tied to a statically + // allocated buffer in libnfc. + phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo = + (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext; + *ppRemoteDevInfo = psRemoteDevInfo; + } + + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_checkndef_callback(void *pContext, + phLibNfc_ChkNdef_Info_t info, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_checkndef_callback", status); + phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext); + if(status == NFCSTATUS_OK) + { + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf_len = info.MaxNdefMsgLength; + nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len); + if (pNdefInfo != NULL) *pNdefInfo = info; + } + else { + if (pNdefInfo != NULL) { + memset(pNdefInfo, 0, sizeof(*pNdefInfo)); + } + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_async_disconnect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + LOG_CALLBACK("nfc_jni_async_disconnect_callback", status); + + if(nfc_jni_ndef_buf) + { + free(nfc_jni_ndef_buf); + } + nfc_jni_ndef_buf = NULL; + nfc_jni_ndef_buf_len = 0; +} + +static phNfc_sData_t *nfc_jni_transceive_buffer; + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + nfc_jni_transceive_buffer = pResBuffer; + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presencecheck_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_formatndef_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_readonly_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* Functions */ +static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e, + jobject o) +{ + NFCSTATUS status; + phLibNfc_Handle handle = 0; + jbyteArray buf = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len; + nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf; + + TRACE("phLibNfc_Ndef_Read()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw, + phLibNfc_Ndef_EBegin, + nfc_jni_tag_rw_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + buf = e->NewByteArray(nfc_jni_ndef_rw.length); + e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length, + (jbyte *)nfc_jni_ndef_rw.buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + + return buf; +} + + +static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e, + jobject o, jbyteArray buf) +{ + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf); + nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_Ndef_Write()"); + TRACE("Ndef Handle :0x%x\n",handle); + TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * Utility to recover poll bytes from target infos + */ +static void set_target_pollBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B"); + + jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingPollBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + jint *techId = e->GetIntArrayElements(techList, 0); + int techListLength = e->GetArrayLength(techList); + + jbyteArray pollBytes = e->NewByteArray(0); + jobjectArray techPollBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(pollBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) + { + /* ISO14443-3A: ATQA/SENS_RES */ + case TARGET_TYPE_ISO14443_3A: + if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) { + // Jewel ATQA is not read and stored by the PN544, but it is fixed + // at {0x00, 0x0C} in the spec. So eJewel can safely be + // translated to {0x00, 0x0C}. + const static jbyte JewelAtqA[2] = {0x00, 0x0C}; + pollBytes = e->NewByteArray(2); + e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA); + } + else { + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA); + } + break; + /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */ + case TARGET_TYPE_ISO14443_3B: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo); + break; + /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */ + case TARGET_TYPE_FELICA: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm), + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode), + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode); + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + pollBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techPollBytes, tech, pollBytes); + } + + e->SetObjectField(tag, f, techPollBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); + +} + +/* + * Utility to recover activation bytes from target infos + */ +static void set_target_activationBytes(JNIEnv *e, jobject tag, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) +{ + jclass tag_cls = e->GetObjectClass(tag); + + jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B"); + jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f); + + if (existingActBytes != NULL) { + return; + } + + jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I"); + jintArray techList = (jintArray) e->GetObjectField(tag, techListField); + int techListLength = e->GetArrayLength(techList); + jint *techId = e->GetIntArrayElements(techList, 0); + + jbyteArray actBytes = e->NewByteArray(0); + jobjectArray techActBytes = e->NewObjectArray(techListLength, + e->GetObjectClass(actBytes), 0); + + for (int tech = 0; tech < techListLength; tech++) { + switch(techId[tech]) { + + /* ISO14443-3A: SAK/SEL_RES */ + case TARGET_TYPE_ISO14443_3A: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak); + break; + /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */ + /* ISO14443-3B & ISO14443-4: HiLayerResp */ + case TARGET_TYPE_ISO14443_4: + // Determine whether -A or -B + if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength); + e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp); + } + else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC || + psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) { + actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength); + e->SetByteArrayRegion(actBytes, 0, + psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength, + (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData); + } + break; + /* ISO15693: response flags (1 byte), DSFID (1 byte) */ + case TARGET_TYPE_ISO15693: + actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags) + + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid)); + e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags); + e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags), + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid), + (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid); + break; + default: + actBytes = e->NewByteArray(0); + break; + } + e->SetObjectArrayElement(techActBytes, tech, actBytes); + } + e->SetObjectField(tag, f, techActBytes); + + e->ReleaseIntArrayElements(techList, techId, 0); +} + +static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status); + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + // Success, set poll & act bytes + set_target_pollBytes(e, o, pRemDevInfo); + set_target_activationBytes(e, o, pRemDevInfo); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e, + jobject o, phLibNfc_Handle handle) +{ + jclass cls; + jfieldID f; + jint status; + struct nfc_jni_callback_data cb_data; + phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL; + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, &pRemDevInfo)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_ReConnect(RW)"); + REENTRANCE_LOCK(); + storedHandle = handle; + status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + + /* Connect Status */ + if(status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e, + jobject o) +{ + // Reconnect is provided by libnfc by just calling connect again + // on the same handle. + int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + if (libNfcType != -1) { + // Note that some tag types are stateless, hence we do not reconnect + // those. Currently those are the Jewel and Iso15693 technologies. + if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) { + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o); + return com_android_nfc_NativeNfcTag_doConnect(e, o, handle); + } + else { + return NFCSTATUS_SUCCESS; + } + } + else { + return NFCSTATUS_REJECTED; + } +} + + +static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jclass cls; + jfieldID f; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_connected_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Reset the stored handle */ + storedHandle = 0; + + nfc_jni_reset_timeout_values(); + + /* Disconnect */ + TRACE("Disconnecting from tag (%x)", handle); + + if (handle == -1) { + // Was never connected to any tag, exit + result = JNI_TRUE; + ALOGE("doDisconnect() - Target already disconnected"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE, + nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + result = JNI_TRUE; + TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected"); + goto clean_and_return; + } + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static uint16_t +crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init ) +{ + uint16_t b, crc = init; + + do { + b = *msg++ ^ (crc & 0xFF); + b ^= (b << 4) & 0xFF; + crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4); + } while( --len ); + + return crc; +} + +static void +nfc_insert_crc_a( uint8_t* msg, size_t len ) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + msg[len] = crc & 0xFF; + msg[len + 1] = (crc >> 8) & 0xFF; +} + +static void +nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2) +{ + uint16_t crc; + + crc = crc_16_ccitt1( msg, len, 0x6363 ); + *byte1 = crc & 0xFF; + *byte2 = (crc >> 8) & 0xFF; +} + +static bool +crc_valid( uint8_t* msg, size_t len) +{ + uint8_t crcByte1, crcByte2; + + nfc_get_crc_a(nfc_jni_transceive_buffer->buffer, + len - 2, &crcByte1, &crcByte2); + + if (msg[len - 2] == crcByte1 && + msg[len - 1] == crcByte2) { + return true; + } + else { + return false; + } + +} + +static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e, + jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + uint8_t offset = 0; + // buf is the pointer to the JNI array and never overwritten, + // outbuf is passed into the transceive - it may be pointed to new memory + // to be extended with CRC. + uint8_t *buf = NULL; + uint32_t buflen; + + uint8_t *outbuf = NULL; + uint32_t outlen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + int res; + phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o); + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + int selectedTech = 0; + int selectedLibNfcType = 0; + jint* technologies = NULL; + bool checkResponseCrc = false; + + jint *targetLost; + if (statusTargetLost != NULL) { + targetLost = e->GetIntArrayElements(statusTargetLost, 0); + if (targetLost != NULL) { + *targetLost = 0; + } + } else { + targetLost = NULL; + } + + memset(&transceive_info, 0, sizeof(transceive_info)); + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + selectedTech = nfc_jni_get_connected_technology(e, o); + selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o); + + buf = outbuf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = outlen = (uint32_t)e->GetArrayLength(data); + + switch (selectedTech) { + case TARGET_TYPE_FELICA: + transceive_info.cmd.FelCmd = phNfc_eFelica_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_MIFARE_CLASSIC: + case TARGET_TYPE_MIFARE_UL: + if (raw) { + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + break; + case TARGET_TYPE_ISO14443_3A: + // Check which libnfc type + if (selectedLibNfcType == phNfc_eJewel_PICC) { + // For the Jewel pipe, CRC is automatically computed + transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw; + transceive_info.addr = 0; + } else { + if (raw) { + // Use Mifare Raw to implement a standard + // ISO14443-3A transceive, with CRC added + transceive_info.cmd.MfCmd = phHal_eMifareRaw; + transceive_info.addr = 0; + // Need to add in the crc here + outbuf = (uint8_t*)malloc(buflen + 2); + outlen += 2; + memcpy(outbuf, buf, buflen); + nfc_insert_crc_a(outbuf, buflen); + + checkResponseCrc = true; + } else { + // Use the mifare pipe + offset = 2; + transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0]; + transceive_info.addr = (uint8_t)buf[1]; + } + + } + break; + case TARGET_TYPE_ISO14443_4: + transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw; + transceive_info.addr = 0; + break; + case TARGET_TYPE_ISO15693: + transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd; + transceive_info.addr = 0; + break; + case TARGET_TYPE_UNKNOWN: + case TARGET_TYPE_ISO14443_3B: + // Not supported + goto clean_and_return; + default: + break; + } + + transceive_info.sSendData.buffer = outbuf + offset; + transceive_info.sSendData.length = outlen - offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, + nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if ((targetLost != NULL) && (status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) { + *targetLost = 1; + } + goto clean_and_return; + } + + /* Copy results back to Java * + * In case of NfcA and raw, also check the CRC in the response + * and cut it off in the returned data. + */ + if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) { + if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) { + result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length - 2, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } + } else { + result = e->NewByteArray(nfc_jni_transceive_buffer->length); + if (result != NULL) { + e->SetByteArrayRegion(result, 0, + nfc_jni_transceive_buffer->length, + (jbyte *)nfc_jni_transceive_buffer->buffer); + } + } +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + if ((outbuf != buf) && (outbuf != NULL)) { + // Buf was extended and re-alloced with crc bytes, free separately + free(outbuf); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)buf, JNI_ABORT); + + if (targetLost != NULL) { + e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0); + } + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o, + jint libnfcType, jint javaType) +{ + jint ndefType = NDEF_UNKNOWN_TYPE; + + switch (libnfcType) { + case phNfc_eJewel_PICC: + ndefType = NDEF_TYPE1_TAG; + break; + case phNfc_eISO14443_3A_PICC: + ndefType = NDEF_TYPE2_TAG;; + break; + case phNfc_eFelica_PICC: + ndefType = NDEF_TYPE3_TAG; + break; + case phNfc_eISO14443_A_PICC: + case phNfc_eISO14443_4A_PICC: + case phNfc_eISO14443_B_PICC: + case phNfc_eISO14443_4B_PICC: + ndefType = NDEF_TYPE4_TAG; + break; + case phNfc_eMifare_PICC: + if (javaType == TARGET_TYPE_MIFARE_UL) { + ndefType = NDEF_TYPE2_TAG; + } else { + ndefType = NDEF_MIFARE_CLASSIC_TAG; + } + break; + case phNfc_eISO15693_PICC: + ndefType = NDEF_ICODE_SLI_TAG; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + return ndefType; +} + +static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo) +{ + phLibNfc_Handle handle = 0; + jint status; + phLibNfc_ChkNdef_Info_t sNdefInfo; + struct nfc_jni_callback_data cb_data; + jint *ndef = e->GetIntArrayElements(ndefinfo, 0); + int apiCardState = NDEF_MODE_UNKNOWN; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + status = NFCSTATUS_NOT_ENOUGH_MEMORY; + goto clean_and_return; + } + cb_data.pContext = &sNdefInfo; + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_Ndef_CheckNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + status = NFCSTATUS_ABORTED; + goto clean_and_return; + } + + status = cb_data.status; + TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status); + + if (status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + ndef[0] = sNdefInfo.MaxNdefMsgLength; + // Translate the card state to know values for the NFC API + switch (sNdefInfo.NdefCardState) { + case PHLIBNFC_NDEF_CARD_INITIALISED: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_READ_ONLY: + apiCardState = NDEF_MODE_READ_ONLY; + break; + case PHLIBNFC_NDEF_CARD_READ_WRITE: + apiCardState = NDEF_MODE_READ_WRITE; + break; + case PHLIBNFC_NDEF_CARD_INVALID: + apiCardState = NDEF_MODE_UNKNOWN; + break; + } + ndef[1] = apiCardState; + +clean_and_return: + e->ReleaseIntArrayElements(ndefinfo, ndef, 0); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return status; +} + +static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + TRACE("phLibNfc_RemoteDev_CheckPresence()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e, + jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire + // is supported. + jboolean result = JNI_FALSE; + + // DESfire has one sak byte and 2 ATQA bytes + if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) && + actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) { + jbyte* poll = e->GetByteArrayElements(pollBytes, NULL); + jbyte* act = e->GetByteArrayElements(actBytes, NULL); + if (act[0] == 0x20 && poll[1] == 0x03) { + uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00}; + // Identifies as DESfire, use get version cmd to be sure + jbyteArray versionCmd = e->NewByteArray(5); + e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd); + jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o, + versionCmd, JNI_TRUE, NULL); + if (respBytes != NULL) { + // Check whether the response matches a typical DESfire + // response. + // libNFC even does more advanced checking than we do + // here, and will only format DESfire's with a certain + // major/minor sw version and NXP as a manufacturer. + // We don't want to do such checking here, to avoid + // having to change code in multiple places. + // A succesful (wrapped) DESFire getVersion command returns + // 9 bytes, with byte 7 0x91 and byte 8 having status + // code 0xAF (these values are fixed and well-known). + int respLength = e->GetArrayLength(respBytes); + jbyte* resp = e->GetByteArrayElements(respBytes, NULL); + if (respLength == 9 && resp[7] == (jbyte)0x91 && + resp[8] == (jbyte)0xAF) { + result = JNI_TRUE; + } + e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT); + } + } + e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT); + e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT); + } + + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + phNfc_sData_t keyBuffer; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_RemoteDev_FormatNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + phNfc_sData_t keyBuffer; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + handle = nfc_jni_get_connected_handle(e, o); + keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL); + keyBuffer.length = e->GetArrayLength(key); + TRACE("phLibNfc_ConvertToReadOnlyNdef()"); + REENTRANCE_LOCK(); + status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback, + (void *)&cb_data); + REENTRANCE_UNLOCK(); + + if(status != NFCSTATUS_PENDING) + { + ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if (cb_data.status == NFCSTATUS_SUCCESS) + { + result = JNI_TRUE; + } + +clean_and_return: + e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT); + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeNfcTag_doDisconnect}, + {"doReconnect", "()I", + (void *)com_android_nfc_NativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", + (void *)com_android_nfc_NativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", + (void *)com_android_nfc_NativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", + (void *)com_android_nfc_NativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", + (void *)com_android_nfc_NativeNfcTag_doCheckNdef}, + {"doRead", "()[B", + (void *)com_android_nfc_NativeNfcTag_doRead}, + {"doWrite", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", + (void *)com_android_nfc_NativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", + (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", + (void *)com_android_nfc_NativeNfcTag_doMakeReadonly}, +}; + +int register_com_android_nfc_NativeNfcTag(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeNfcTag", + gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp new file mode 100644 index 0000000..b3cc6e3 --- /dev/null +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -0,0 +1,490 @@ + +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "com_android_nfc.h" + +extern uint8_t device_connected_flag; + +namespace android { + +extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat); + +/* + * Callbacks + */ +static void nfc_jni_presence_check_callback(void* pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_presence_check_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_connect_callback(void *pContext, + phLibNfc_Handle hRemoteDev, + phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t * psGeneralBytes = (phNfc_sData_t *)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_connect_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + psGeneralBytes->length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length; + psGeneralBytes->buffer = (uint8_t*)malloc(psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); + psGeneralBytes->buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_disconnect_callback(void *pContext, phLibNfc_Handle hRemoteDev, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_disconnect_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_receive_callback(void *pContext, phNfc_sData_t *data, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + phNfc_sData_t **ptr = (phNfc_sData_t **)pCallbackData->pContext; + LOG_CALLBACK("nfc_jni_receive_callback", status); + + if(status == NFCSTATUS_SUCCESS) + { + *ptr = data; + } + else + { + *ptr = NULL; + } + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static void nfc_jni_send_callback(void *pContext, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_send_callback", status); + + /* Report the callback status and wake up the caller */ + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +/* + * Functions + */ + +static void nfc_jni_transceive_callback(void *pContext, + phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status) +{ + struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; + LOG_CALLBACK("nfc_jni_transceive_callback", status); + + /* Report the callback data and wake up the caller */ + pCallbackData->pContext = pResBuffer; + pCallbackData->status = status; + sem_post(&pCallbackData->sem); +} + +static jboolean com_android_nfc_NativeP2pDevice_doConnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + NFCSTATUS status; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + jclass target_cls = NULL; + jobject tag; + jmethodID ctor; + jfieldID f; + jbyteArray generalBytes = NULL; + phNfc_sData_t sGeneralBytes; + unsigned int i; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)&sGeneralBytes)) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Connect(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback, (void*)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Connect(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Set General Bytes */ + target_cls = e->GetObjectClass(o); + + f = e->GetFieldID(target_cls, "mGeneralBytes", "[B"); + + TRACE("General Bytes Length = %d", sGeneralBytes.length); + TRACE("General Bytes ="); + for(i=0;iNewByteArray(sGeneralBytes.length); + + e->SetByteArrayRegion(generalBytes, 0, + sGeneralBytes.length, + (jbyte *)sGeneralBytes.buffer); + + e->SetObjectField(o, f, generalBytes); + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + /* Restart the polling loop if the connection failed */ + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jboolean com_android_nfc_NativeP2pDevice_doDisconnect(JNIEnv *e, jobject o) +{ + phLibNfc_Handle handle = 0; + jboolean result = JNI_FALSE; + NFCSTATUS status; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Disconnect */ + TRACE("Disconnecting from target (handle = 0x%x)", handle); + + /* NativeNfcTag waits for tag to leave the field here with presence check. + * We do not in P2P path because presence check is not safe while transceive may be + * in progress. + */ + + TRACE("phLibNfc_RemoteDev_Disconnect()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,nfc_jni_disconnect_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + if(status == NFCSTATUS_TARGET_NOT_CONNECTED) + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed: Target not connected"); + } + else + { + ALOGE("phLibNfc_RemoteDev_Disconnect() failed"); + nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e)); + } + + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Disconnect() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + /* Disconnect Status */ + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + /* Reset device connected flag */ + device_connected_flag = 0; + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +static jbyteArray com_android_nfc_NativeP2pDevice_doTransceive(JNIEnv *e, + jobject o, jbyteArray data) +{ + NFCSTATUS status; + uint8_t offset = 2; + uint8_t *buf; + uint32_t buflen; + phLibNfc_sTransceiveInfo_t transceive_info; + jbyteArray result = NULL; + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + phNfc_sData_t * receive_buffer = NULL; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)receive_buffer)) + { + goto clean_and_return; + } + + /* Transceive*/ + TRACE("Transceive data to target (handle = 0x%x)", handle); + + buf = (uint8_t *)e->GetByteArrayElements(data, NULL); + buflen = (uint32_t)e->GetArrayLength(data); + + TRACE("Buffer Length = %d\n", buflen); + + transceive_info.sSendData.buffer = buf; //+ offset; + transceive_info.sSendData.length = buflen; //- offset; + transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024); + transceive_info.sRecvData.length = 1024; + + if(transceive_info.sRecvData.buffer == NULL) + { + goto clean_and_return; + } + + TRACE("phLibNfc_RemoteDev_Transceive(P2P)"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info, nfc_jni_transceive_callback, (void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Transceive(P2P) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + /* Copy results back to Java */ + result = e->NewByteArray(receive_buffer->length); + if(result != NULL) + e->SetByteArrayRegion(result, 0, + receive_buffer->length, + (jbyte *)receive_buffer->buffer); + +clean_and_return: + if(transceive_info.sRecvData.buffer != NULL) + { + free(transceive_info.sRecvData.buffer); + } + + e->ReleaseByteArrayElements(data, + (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT); + + nfc_cb_data_deinit(&cb_data); + + CONCURRENCY_UNLOCK(); + + return result; +} + + +static jbyteArray com_android_nfc_NativeP2pDevice_doReceive( + JNIEnv *e, jobject o) +{ + NFCSTATUS status; + struct timespec ts; + phLibNfc_Handle handle; + jbyteArray buf = NULL; + static phNfc_sData_t *data; + struct nfc_jni_callback_data cb_data; + + CONCURRENCY_LOCK(); + + handle = nfc_jni_get_p2p_device_handle(e, o); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, (void*)data)) + { + goto clean_and_return; + } + + /* Receive */ + TRACE("phLibNfc_RemoteDev_Receive()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Receive(handle, nfc_jni_receive_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Receive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(data == NULL) + { + goto clean_and_return; + } + + buf = e->NewByteArray(data->length); + e->SetByteArrayRegion(buf, 0, data->length, (jbyte *)data->buffer); + +clean_and_return: + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return buf; +} + +static jboolean com_android_nfc_NativeP2pDevice_doSend( + JNIEnv *e, jobject o, jbyteArray buf) +{ + NFCSTATUS status; + phNfc_sData_t data; + jboolean result = JNI_FALSE; + struct nfc_jni_callback_data cb_data; + + phLibNfc_Handle handle = nfc_jni_get_p2p_device_handle(e, o); + + CONCURRENCY_LOCK(); + + /* Create the local semaphore */ + if (!nfc_cb_data_init(&cb_data, NULL)) + { + goto clean_and_return; + } + + /* Send */ + TRACE("Send data to the Initiator (handle = 0x%x)", handle); + + data.length = (uint32_t)e->GetArrayLength(buf); + data.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL); + + TRACE("phLibNfc_RemoteDev_Send()"); + REENTRANCE_LOCK(); + status = phLibNfc_RemoteDev_Send(handle, &data, nfc_jni_send_callback,(void *)&cb_data); + REENTRANCE_UNLOCK(); + if(status != NFCSTATUS_PENDING) + { + ALOGE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + goto clean_and_return; + } + TRACE("phLibNfc_RemoteDev_Send() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); + + /* Wait for callback response */ + if(sem_wait(&cb_data.sem)) + { + ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno); + goto clean_and_return; + } + + if(cb_data.status != NFCSTATUS_SUCCESS) + { + goto clean_and_return; + } + + result = JNI_TRUE; + +clean_and_return: + if (result != JNI_TRUE) + { + e->ReleaseByteArrayElements(buf, (jbyte *)data.buffer, JNI_ABORT); + } + nfc_cb_data_deinit(&cb_data); + CONCURRENCY_UNLOCK(); + return result; +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doConnect}, + {"doDisconnect", "()Z", + (void *)com_android_nfc_NativeP2pDevice_doDisconnect}, + {"doTransceive", "([B)[B", + (void *)com_android_nfc_NativeP2pDevice_doTransceive}, + {"doReceive", "()[B", + (void *)com_android_nfc_NativeP2pDevice_doReceive}, + {"doSend", "([B)Z", + (void *)com_android_nfc_NativeP2pDevice_doSend}, +}; + +int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, + "com/android/nfc/nxp/NativeP2pDevice", + gMethods, NELEM(gMethods)); +} + +} // namepspace android diff --git a/nxp/jni/com_android_nfc_list.cpp b/nxp/jni/com_android_nfc_list.cpp new file mode 100644 index 0000000..f0487d3 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "NFC_LIST" + +bool listInit(listHead* pList) +{ + pList->pFirst = NULL; + if(pthread_mutex_init(&pList->mutex, NULL) == -1) + { + ALOGE("Mutex creation failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listDestroy(listHead* pList) +{ + bool bListNotEmpty = true; + while (bListNotEmpty) { + bListNotEmpty = listGetAndRemoveNext(pList, NULL); + } + + if(pthread_mutex_destroy(&pList->mutex) == -1) + { + ALOGE("Mutex destruction failed (errno=0x%08x)", errno); + return false; + } + + return true; +} + +bool listAdd(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pLastNode; + bool result; + + /* Create node */ + pNode = (struct listNode*)malloc(sizeof(listNode)); + if (pNode == NULL) + { + result = false; + ALOGE("Failed to malloc"); + goto clean_and_return; + } + TRACE("Allocated node: %8p (%8p)", pNode, pData); + pNode->pData = pData; + pNode->pNext = NULL; + + pthread_mutex_lock(&pList->mutex); + + /* Add the node to the list */ + if (pList->pFirst == NULL) + { + /* Set the node as the head */ + pList->pFirst = pNode; + } + else + { + /* Seek to the end of the list */ + pLastNode = pList->pFirst; + while(pLastNode->pNext != NULL) + { + pLastNode = pLastNode->pNext; + } + + /* Add the node to the current list */ + pLastNode->pNext = pNode; + } + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listRemove(listHead* pList, void* pData) +{ + struct listNode* pNode; + struct listNode* pRemovedNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst == NULL) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + pNode = pList->pFirst; + if (pList->pFirst->pData == pData) + { + /* Get the removed node */ + pRemovedNode = pNode; + + /* Remove the first node */ + pList->pFirst = pList->pFirst->pNext; + } + else + { + while (pNode->pNext != NULL) + { + if (pNode->pNext->pData == pData) + { + /* Node found ! */ + break; + } + pNode = pNode->pNext; + } + + if (pNode->pNext == NULL) + { + /* Node not found */ + result = false; + ALOGE("Failed to deallocate (not found %8p)", pData); + goto clean_and_return; + } + + /* Get the removed node */ + pRemovedNode = pNode->pNext; + + /* Remove the node from the list */ + pNode->pNext = pNode->pNext->pNext; + } + + /* Deallocate the node */ + TRACE("Deallocating node: %8p (%8p)", pRemovedNode, pRemovedNode->pData); + free(pRemovedNode); + + result = true; + +clean_and_return: + pthread_mutex_unlock(&pList->mutex); + return result; +} + +bool listGetAndRemoveNext(listHead* pList, void** ppData) +{ + struct listNode* pNode; + bool result; + + pthread_mutex_lock(&pList->mutex); + + if (pList->pFirst) + { + /* Empty list */ + ALOGE("Failed to deallocate (list empty)"); + result = false; + goto clean_and_return; + } + + /* Work on the first node */ + pNode = pList->pFirst; + + /* Return the data */ + if (ppData != NULL) + { + *ppData = pNode->pData; + } + + /* Remove and deallocate the node */ + pList->pFirst = pNode->pNext; + TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData); + free(pNode); + + result = true; + +clean_and_return: + listDump(pList); + pthread_mutex_unlock(&pList->mutex); + return result; +} + +void listDump(listHead* pList) +{ + struct listNode* pNode = pList->pFirst; + + TRACE("Node dump:"); + while (pNode != NULL) + { + TRACE("- %8p (%8p)", pNode, pNode->pData); + pNode = pNode->pNext; + } +} diff --git a/nxp/jni/com_android_nfc_list.h b/nxp/jni/com_android_nfc_list.h new file mode 100644 index 0000000..22b4f09 --- /dev/null +++ b/nxp/jni/com_android_nfc_list.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COM_ANDROID_NFC_LIST_H__ +#define __COM_ANDROID_NFC_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct listNode +{ + void* pData; + struct listNode* pNext; +}; + +struct listHead +{ + listNode* pFirst; + pthread_mutex_t mutex; +}; + +bool listInit(listHead* pList); +bool listDestroy(listHead* pList); +bool listAdd(listHead* pList, void* pData); +bool listRemove(listHead* pList, void* pData); +bool listGetAndRemoveNext(listHead* pList, void** ppData); +void listDump(listHead* pList); + +#ifdef __cplusplus +} +#endif + +#endif /* __COM_ANDROID_NFC_LIST_H__ */ diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..f969627 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || + ndefType == Ndef.TYPE_MIFARE_CLASSIC); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + return 0; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // Not supported on the PN544 + return false; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eddde94 --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = false; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + status = doConnect(mTechHandles[i]); + } else { + // Connect to a tech with a different handle + status = reconnectWithStatus(mTechHandles[i]); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + status = 0; + } else { + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + status = -1; + } else { + status = 0; + } + } + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { + // These are always formatable + return true; + } + if (hasTech(TagTechnology.NFC_V)) { + // Currently libnfc only formats NXP NFC-V tags + if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { + return true; + } else { + return false; + } + } + // For ISO-DEP, call native code to determine at lower level if format + // is possible. It will need NFC-A poll/activation time bytes for this. + if (hasTech(TagTechnology.ISO_DEP)) { + int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); + if (nfcaTechIndex != -1) { + return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], + mTechActBytes[nfcaTechIndex]); + } else { + return false; + } + } else { + // Formatting not supported by libNFC + return false; + } + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nxp/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 602b25d..3e7a6b5 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -23,8 +23,8 @@ import com.android.nfc.DeviceHost.LlcpSocket; import com.android.nfc.DeviceHost.NfcDepEndpoint; import com.android.nfc.DeviceHost.TagEndpoint; import com.android.nfc.handover.HandoverManager; -import com.android.nfc.nxp.NativeNfcManager; -import com.android.nfc.nxp.NativeNfcSecureElement; +import com.android.nfc.dhimpl.NativeNfcManager; +import com.android.nfc.dhimpl.NativeNfcSecureElement; import android.app.Application; import android.app.KeyguardManager; diff --git a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java b/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java deleted file mode 100755 index c9d3b5d..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpConnectionlessSocket.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpPacket; - -import java.io.IOException; - -/** - * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used - * in a connectionless communication - */ -public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { - - private int mHandle; - private int mSap; - private int mLinkMiu; - - public NativeLlcpConnectionlessSocket() { } - - public native boolean doSendTo(int sap, byte[] data); - - public native LlcpPacket doReceiveFrom(int linkMiu); - - public native boolean doClose(); - - @Override - public int getLinkMiu(){ - return mLinkMiu; - } - - @Override - public int getSap(){ - return mSap; - } - - @Override - public void send(int sap, byte[] data) throws IOException { - if (!doSendTo(sap, data)) { - throw new IOException(); - } - } - - @Override - public LlcpPacket receive() throws IOException { - LlcpPacket packet = doReceiveFrom(mLinkMiu); - if (packet == null) { - throw new IOException(); - } - return packet; - } - - public int getHandle(){ - return mHandle; - } - - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java b/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java deleted file mode 100755 index 531afd8..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpServiceSocket.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.DeviceHost.LlcpSocket; - -import java.io.IOException; - -/** - * LlcpServiceSocket represents a LLCP Service to be used in a - * Connection-oriented communication - */ -public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { - private int mHandle; - private int mLocalMiu; - private int mLocalRw; - private int mLocalLinearBufferLength; - private int mSap; - private String mServiceName; - - public NativeLlcpServiceSocket(){ } - - private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); - @Override - public LlcpSocket accept() throws IOException { - LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); - if (socket == null) throw new IOException(); - return socket; - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } -} diff --git a/src/com/android/nfc/nxp/NativeLlcpSocket.java b/src/com/android/nfc/nxp/NativeLlcpSocket.java deleted file mode 100755 index a337d35..0000000 --- a/src/com/android/nfc/nxp/NativeLlcpSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; - -import java.io.IOException; - -/** - * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a - * connection-oriented communication - */ -public class NativeLlcpSocket implements DeviceHost.LlcpSocket { - private int mHandle; - private int mSap; - private int mLocalMiu; - private int mLocalRw; - - public NativeLlcpSocket(){ } - - private native boolean doConnect(int nSap); - @Override - public void connectToSap(int sap) throws IOException { - if (!doConnect(sap)) { - throw new IOException(); - } - } - - private native boolean doConnectBy(String sn); - @Override - public void connectToService(String serviceName) throws IOException { - if (!doConnectBy(serviceName)) { - throw new IOException(); - } - } - - private native boolean doClose(); - @Override - public void close() throws IOException { - if (!doClose()) { - throw new IOException(); - } - } - - private native boolean doSend(byte[] data); - @Override - public void send(byte[] data) throws IOException { - if (!doSend(data)) { - throw new IOException(); - } - } - - private native int doReceive(byte[] recvBuff); - @Override - public int receive(byte[] recvBuff) throws IOException { - int receiveLength = doReceive(recvBuff); - if (receiveLength == -1) { - throw new IOException(); - } - return receiveLength; - } - - private native int doGetRemoteSocketMiu(); - @Override - public int getRemoteMiu() { return doGetRemoteSocketMiu(); } - - private native int doGetRemoteSocketRw(); - @Override - public int getRemoteRw() { return doGetRemoteSocketRw(); } - - @Override - public int getLocalSap(){ - return mSap; - } - - @Override - public int getLocalMiu(){ - return mLocalMiu; - } - - @Override - public int getLocalRw(){ - return mLocalRw; - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcManager.java b/src/com/android/nfc/nxp/NativeNfcManager.java deleted file mode 100755 index 4bd8c24..0000000 --- a/src/com/android/nfc/nxp/NativeNfcManager.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost; -import com.android.nfc.LlcpException; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.content.SharedPreferences; -import android.nfc.ErrorCodes; -import android.nfc.tech.Ndef; -import android.nfc.tech.TagTechnology; -import android.util.Log; - -import java.io.File; - -/** - * Native interface to the NFC Manager functions - */ -public class NativeNfcManager implements DeviceHost { - private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; - - static { - System.loadLibrary("nfc_jni"); - } - - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; - - /* Native structure */ - private int mNative; - - private final DeviceHostListener mListener; - private final Context mContext; - - public NativeNfcManager(Context context, DeviceHostListener listener) { - mListener = listener; - initializeNativeStructure(); - mContext = context; - } - - public native boolean initializeNativeStructure(); - - private native boolean doDownload(); - - public native int doGetLastError(); - - @Override - public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } - } - - private native boolean doInitialize(); - - @Override - public boolean initialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { - try { - Thread.sleep (12000); - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - } catch (InterruptedException e) { } - } - - return doInitialize(); - } - - private native boolean doDeinitialize(); - - @Override - public boolean deinitialize() { - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - - editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); - editor.apply(); - - return doDeinitialize(); - } - - @Override - public native void enableDiscovery(); - - @Override - public native void disableDiscovery(); - - @Override - public native int[] doGetSecureElementList(); - - @Override - public native void doSelectSecureElement(); - - @Override - public native void doDeselectSecureElement(); - - - private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, - String sn); - - @Override - public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) - throws LlcpException { - LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength); - @Override - public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, - int rw, int linearBufferLength) throws LlcpException { - LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, - int linearBufferLength); - @Override - public LlcpSocket createLlcpSocket(int sap, int miu, int rw, - int linearBufferLength) throws LlcpException { - LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); - if (socket != null) { - return socket; - } else { - /* Get Error Status */ - int error = doGetLastError(); - - Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); - - switch (error) { - case ErrorCodes.ERROR_BUFFER_TO_SMALL: - case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: - throw new LlcpException(error); - default: - throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); - } - } - } - - @Override - public native boolean doCheckLlcp(); - - @Override - public native boolean doActivateLlcp(); - - private native void doResetTimeouts(); - - @Override - public void resetTimeouts() { - doResetTimeouts(); - } - - @Override - public native void doAbort(); - - private native boolean doSetTimeout(int tech, int timeout); - @Override - public boolean setTimeout(int tech, int timeout) { - return doSetTimeout(tech, timeout); - } - - private native int doGetTimeout(int tech); - @Override - public int getTimeout(int tech) { - return doGetTimeout(tech); - } - - - @Override - public boolean canMakeReadOnly(int ndefType) { - return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || - ndefType == Ndef.TYPE_MIFARE_CLASSIC); - } - - @Override - public int getMaxTransceiveLength(int technology) { - switch (technology) { - case (TagTechnology.NFC_A): - case (TagTechnology.MIFARE_CLASSIC): - case (TagTechnology.MIFARE_ULTRALIGHT): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.NFC_B): - return 0; // PN544 does not support transceive of raw NfcB - case (TagTechnology.NFC_V): - return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC - case (TagTechnology.ISO_DEP): - /* The maximum length of a normal IsoDep frame consists of: - * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes - * such a frame is supported. Extended length frames however - * are not supported. - */ - return 261; // Will be automatically split in two frames on the RF layer - case (TagTechnology.NFC_F): - return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC - default: - return 0; - } - - } - - private native void doSetP2pInitiatorModes(int modes); - @Override - public void setP2pInitiatorModes(int modes) { - doSetP2pInitiatorModes(modes); - } - - private native void doSetP2pTargetModes(int modes); - @Override - public void setP2pTargetModes(int modes) { - doSetP2pTargetModes(modes); - } - - public boolean getExtendedLengthApdusSupported() { - // Not supported on the PN544 - return false; - } - - private native String doDump(); - @Override - public String dump() { - return doDump(); - } - - /** - * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) - */ - private void notifyNdefMessageListeners(NativeNfcTag tag) { - mListener.onRemoteEndpointDiscovered(tag); - } - - /** - * Notifies transaction - */ - private void notifyTargetDeselected() { - mListener.onCardEmulationDeselected(); - } - - /** - * Notifies transaction - */ - private void notifyTransactionListeners(byte[] aid) { - mListener.onCardEmulationAidSelected(aid); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkActivation(NativeP2pDevice device) { - mListener.onLlcpLinkActivated(device); - } - - /** - * Notifies P2P Device detected, to activate LLCP link - */ - private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { - mListener.onLlcpLinkDeactivated(device); - } - - private void notifySeFieldActivated() { - mListener.onRemoteFieldActivated(); - } - - private void notifySeFieldDeactivated() { - mListener.onRemoteFieldDeactivated(); - } - - private void notifySeApduReceived(byte[] apdu) { - mListener.onSeApduReceived(apdu); - } - - private void notifySeEmvCardRemoval() { - mListener.onSeEmvCardRemoval(); - } - - private void notifySeMifareAccess(byte[] block) { - mListener.onSeMifareAccess(block); - } -} diff --git a/src/com/android/nfc/nxp/NativeNfcSecureElement.java b/src/com/android/nfc/nxp/NativeNfcSecureElement.java deleted file mode 100755 index 88f9b9d..0000000 --- a/src/com/android/nfc/nxp/NativeNfcSecureElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import android.content.Context; -import android.content.SharedPreferences; - - -/** - * Native interface to the NFC Secure Element functions - * - * {@hide} - */ -public class NativeNfcSecureElement { - - static final String PREF_SE_WIRED = "se_wired"; - - private final Context mContext; - - SharedPreferences mPrefs; - SharedPreferences.Editor mPrefsEditor; - - public NativeNfcSecureElement(Context context) { - mContext = context; - - mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); - mPrefsEditor = mPrefs.edit(); - } - - private native int doNativeOpenSecureElementConnection(); - - public int doOpenSecureElementConnection() { - mPrefsEditor.putBoolean(PREF_SE_WIRED, true); - mPrefsEditor.apply(); - - return doNativeOpenSecureElementConnection(); - } - - private native boolean doNativeDisconnectSecureElementConnection(int handle); - - public boolean doDisconnect(int handle) { - mPrefsEditor.putBoolean(PREF_SE_WIRED, false); - mPrefsEditor.apply(); - - return doNativeDisconnectSecureElementConnection(handle); - } - - public native byte[] doTransceive(int handle, byte[] data); - - public native int[] doGetTechList(int handle); - - public native byte [] doGetUid(int handle); -} diff --git a/src/com/android/nfc/nxp/NativeNfcTag.java b/src/com/android/nfc/nxp/NativeNfcTag.java deleted file mode 100755 index 8996dfb..0000000 --- a/src/com/android/nfc/nxp/NativeNfcTag.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.TagEndpoint; - -import android.nfc.FormatException; -import android.nfc.NdefMessage; -import android.nfc.tech.IsoDep; -import android.nfc.tech.MifareClassic; -import android.nfc.tech.MifareUltralight; -import android.nfc.tech.Ndef; -import android.nfc.tech.NfcA; -import android.nfc.tech.NfcB; -import android.nfc.tech.NfcF; -import android.nfc.tech.NfcV; -import android.nfc.tech.TagTechnology; -import android.os.Bundle; -import android.util.Log; - -/** - * Native interface to the NFC tag functions - */ -public class NativeNfcTag implements TagEndpoint { - static final boolean DBG = false; - - static final int STATUS_CODE_TARGET_LOST = 146; - - private int[] mTechList; - private int[] mTechHandles; - private int[] mTechLibNfcTypes; - private Bundle[] mTechExtras; - private byte[][] mTechPollBytes; - private byte[][] mTechActBytes; - private byte[] mUid; - - // mConnectedHandle stores the *real* libnfc handle - // that we're connected to. - private int mConnectedHandle; - - // mConnectedTechIndex stores to which technology - // the upper layer stack is connected. Note that - // we may be connected to a libnfchandle without being - // connected to a technology - technology changes - // may occur runtime, whereas the underlying handle - // could stay present. Usually all technologies are on the - // same handle, with the exception of multi-protocol - // tags. - private int mConnectedTechIndex; // Index in mTechHandles - - private final String TAG = "NativeNfcTag"; - - private boolean mIsPresent; // Whether the tag is known to be still present - - private PresenceCheckWatchdog mWatchdog; - class PresenceCheckWatchdog extends Thread { - - private int watchdogTimeout = 125; - - private boolean isPresent = true; - private boolean isStopped = false; - private boolean isPaused = false; - private boolean doCheck = true; - - public synchronized void pause() { - isPaused = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void doResume() { - isPaused = false; - // We don't want to resume presence checking immediately, - // but go through at least one more wait period. - doCheck = false; - this.notifyAll(); - } - - public synchronized void end() { - isStopped = true; - doCheck = false; - this.notifyAll(); - } - - public synchronized void setTimeout(int timeout) { - watchdogTimeout = timeout; - doCheck = false; // Do it only after we have waited "timeout" ms again - this.notifyAll(); - } - - @Override - public synchronized void run() { - if (DBG) Log.d(TAG, "Starting background presence check"); - while (isPresent && !isStopped) { - try { - if (!isPaused) { - doCheck = true; - } - this.wait(watchdogTimeout); - if (doCheck) { - isPresent = doPresenceCheck(); - } else { - // 1) We are paused, waiting for unpause - // 2) We just unpaused, do pres check in next iteration - // (after watchdogTimeout ms sleep) - // 3) We just set the timeout, wait for this timeout - // to expire once first. - // 4) We just stopped, exit loop anyway - } - } catch (InterruptedException e) { - // Activity detected, loop - } - } - mIsPresent = false; - // Restart the polling loop - - Log.d(TAG, "Tag lost, restarting polling loop"); - doDisconnect(); - if (DBG) Log.d(TAG, "Stopping background presence check"); - } - } - - private native int doConnect(int handle); - public synchronized int connectWithStatus(int technology) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == technology) { - // Get the handle and connect, if not already connected - if (mConnectedHandle != mTechHandles[i]) { - // We're not yet connected to this handle, there are - // a few scenario's here: - // 1) We are not connected to anything yet - allow - // 2) We are connected to a technology which has - // a different handle (multi-protocol tag); we support - // switching to that. - if (mConnectedHandle == -1) { - // Not connected yet - status = doConnect(mTechHandles[i]); - } else { - // Connect to a tech with a different handle - status = reconnectWithStatus(mTechHandles[i]); - } - if (status == 0) { - mConnectedHandle = mTechHandles[i]; - mConnectedTechIndex = i; - } - } else { - // 1) We are connected to a technology which has the same - // handle; we do not support connecting at a different - // level (libnfc auto-activates to the max level on - // any handle). - // 2) We are connecting to the ndef technology - always - // allowed. - if ((technology == TagTechnology.NDEF) || - (technology == TagTechnology.NDEF_FORMATABLE)) { - status = 0; - } else { - if ((technology != TagTechnology.ISO_DEP) && - (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { - // Don't allow to connect a -4 tag at a different level - // than IsoDep, as this is not supported by - // libNFC. - status = -1; - } else { - status = 0; - } - } - if (status == 0) { - mConnectedTechIndex = i; - // Handle was already identical - } - } - break; - } - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean connect(int technology) { - return connectWithStatus(technology) == 0; - } - - @Override - public synchronized void startPresenceChecking() { - // Once we start presence checking, we allow the upper layers - // to know the tag is in the field. - mIsPresent = true; - if (mWatchdog == null) { - mWatchdog = new PresenceCheckWatchdog(); - mWatchdog.start(); - } - } - - @Override - public synchronized boolean isPresent() { - // Returns whether the tag is still in the field to the best - // of our knowledge. - return mIsPresent; - } - native boolean doDisconnect(); - @Override - public synchronized boolean disconnect() { - boolean result = false; - - mIsPresent = false; - if (mWatchdog != null) { - // Watchdog has already disconnected or will do it - mWatchdog.end(); - try { - mWatchdog.join(); - } catch (InterruptedException e) { - // Should never happen. - } - mWatchdog = null; - result = true; - } else { - result = doDisconnect(); - } - - mConnectedTechIndex = -1; - mConnectedHandle = -1; - return result; - } - - native int doReconnect(); - public synchronized int reconnectWithStatus() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doReconnect(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean reconnect() { - return reconnectWithStatus() == 0; - } - - native int doHandleReconnect(int handle); - public synchronized int reconnectWithStatus(int handle) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doHandleReconnect(handle); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - - private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); - @Override - public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doTransceive(data, raw, returnCode); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native int doCheckNdef(int[] ndefinfo); - private synchronized int checkNdefWithStatus(int[] ndefinfo) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - int status = doCheckNdef(ndefinfo); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return status; - } - @Override - public synchronized boolean checkNdef(int[] ndefinfo) { - return checkNdefWithStatus(ndefinfo) == 0; - } - - private native byte[] doRead(); - @Override - public synchronized byte[] readNdef() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - byte[] result = doRead(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - private native boolean doWrite(byte[] buf); - @Override - public synchronized boolean writeNdef(byte[] buf) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doWrite(buf); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doPresenceCheck(); - @Override - public synchronized boolean presenceCheck() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doPresenceCheck(); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doNdefFormat(byte[] key); - @Override - public synchronized boolean formatNdef(byte[] key) { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result = doNdefFormat(key); - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doMakeReadonly(byte[] key); - @Override - public synchronized boolean makeReadOnly() { - if (mWatchdog != null) { - mWatchdog.pause(); - } - boolean result; - if (hasTech(TagTechnology.MIFARE_CLASSIC)) { - result = doMakeReadonly(MifareClassic.KEY_DEFAULT); - } else { - // No key needed for other technologies - result = doMakeReadonly(new byte[] {}); - } - if (mWatchdog != null) { - mWatchdog.doResume(); - } - return result; - } - - native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); - @Override - public synchronized boolean isNdefFormatable() { - if (hasTech(TagTechnology.MIFARE_CLASSIC) || hasTech(TagTechnology.MIFARE_ULTRALIGHT)) { - // These are always formatable - return true; - } - if (hasTech(TagTechnology.NFC_V)) { - // Currently libnfc only formats NXP NFC-V tags - if (mUid[5] >= 1 && mUid[5] <= 3 && mUid[6] == 0x04) { - return true; - } else { - return false; - } - } - // For ISO-DEP, call native code to determine at lower level if format - // is possible. It will need NFC-A poll/activation time bytes for this. - if (hasTech(TagTechnology.ISO_DEP)) { - int nfcaTechIndex = getTechIndex(TagTechnology.NFC_A); - if (nfcaTechIndex != -1) { - return doIsIsoDepNdefFormatable(mTechPollBytes[nfcaTechIndex], - mTechActBytes[nfcaTechIndex]); - } else { - return false; - } - } else { - // Formatting not supported by libNFC - return false; - } - } - - @Override - public int getHandle() { - // This is just a handle for the clients; it can simply use the first - // technology handle we have. - if (mTechHandles.length > 0) { - return mTechHandles[0]; - } else { - return 0; - } - } - - @Override - public byte[] getUid() { - return mUid; - } - - @Override - public int[] getTechList() { - return mTechList; - } - - private int getConnectedHandle() { - return mConnectedHandle; - } - - private int getConnectedLibNfcType() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { - return mTechLibNfcTypes[mConnectedTechIndex]; - } else { - return 0; - } - } - - @Override - public int getConnectedTechnology() { - if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { - return mTechList[mConnectedTechIndex]; - } else { - return 0; - } - } - native int doGetNdefType(int libnfctype, int javatype); - private int getNdefType(int libnfctype, int javatype) { - return doGetNdefType(libnfctype, javatype); - } - - private void addTechnology(int tech, int handle, int libnfctype) { - int[] mNewTechList = new int[mTechList.length + 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); - mNewTechList[mTechList.length] = tech; - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length + 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); - mNewHandleList[mTechHandles.length] = handle; - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); - mNewTypeList[mTechLibNfcTypes.length] = libnfctype; - mTechLibNfcTypes = mNewTypeList; - } - - @Override - public void removeTechnology(int tech) { - synchronized (this) { - int techIndex = getTechIndex(tech); - if (techIndex != -1) { - int[] mNewTechList = new int[mTechList.length - 1]; - System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); - System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, - mTechList.length - techIndex - 1); - mTechList = mNewTechList; - - int[] mNewHandleList = new int[mTechHandles.length - 1]; - System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); - System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, - mTechHandles.length - techIndex - 1); - mTechHandles = mNewHandleList; - - int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; - System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); - System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, - mTechLibNfcTypes.length - techIndex - 1); - mTechLibNfcTypes = mNewTypeList; - } - } - } - - public void addNdefFormatableTechnology(int handle, int libnfcType) { - synchronized (this) { - addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); - } - } - - // This method exists to "patch in" the ndef technologies, - // which is done inside Java instead of the native JNI code. - // To not create some nasty dependencies on the order on which things - // are called (most notably getTechExtras()), it needs some additional - // checking. - public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, - int javaType, int maxLength, int cardState) { - synchronized (this) { - addTechnology(TagTechnology.NDEF, handle, libnfcType); - - Bundle extras = new Bundle(); - extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); - extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); - extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); - extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); - - if (mTechExtras == null) { - // This will build the tech extra's for the first time, - // including a NULL ref for the NDEF tech we generated above. - Bundle[] builtTechExtras = getTechExtras(); - builtTechExtras[builtTechExtras.length - 1] = extras; - } - else { - // Tech extras were built before, patch the NDEF one in - Bundle[] oldTechExtras = getTechExtras(); - Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; - System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); - newTechExtras[oldTechExtras.length] = extras; - mTechExtras = newTechExtras; - } - - - } - } - - private int getTechIndex(int tech) { - int techIndex = -1; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - techIndex = i; - break; - } - } - return techIndex; - } - - private boolean hasTech(int tech) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech) { - hasTech = true; - break; - } - } - return hasTech; - } - - private boolean hasTechOnHandle(int tech, int handle) { - boolean hasTech = false; - for (int i = 0; i < mTechList.length; i++) { - if (mTechList[i] == tech && mTechHandles[i] == handle) { - hasTech = true; - break; - } - } - return hasTech; - - } - - private boolean isUltralightC() { - /* Make a best-effort attempt at classifying ULTRALIGHT - * vs ULTRALIGHT-C (based on NXP's public AN1303). - * The memory layout is as follows: - * Page # BYTE1 BYTE2 BYTE3 BYTE4 - * 2 INT1 INT2 LOCK LOCK - * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) - * 4 DATA DATA DATA DATA (version info if factory-state) - * - * Read four blocks from page 2, which will get us both - * the lock page, the OTP page and the version info. - */ - boolean isUltralightC = false; - byte[] readCmd = { 0x30, 0x02 }; - int[] retCode = new int[2]; - byte[] respData = transceive(readCmd, false, retCode); - if (respData != null && respData.length == 16) { - // Check the lock bits (last 2 bytes in page2) - // and the OTP bytes (entire page 3) - if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && - respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { - // Very likely to be a blank card, look at version info - // in page 4. - if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { - // This is Ultralight-C - isUltralightC = true; - } else { - // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight - // as a fallback if it's anything else - isUltralightC = false; - } - } else { - // See if we can find the NDEF CC in the OTP page and if it's - // smaller than major version two - if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { - // OK, got NDEF. Technically we'd have to search for the - // NDEF TLV as well. However, this would add too much - // time for discovery and we can make already make a good guess - // with the data we have here. Byte 2 of the OTP page - // indicates the size of the tag - 0x06 is UL, anything - // above indicates UL-C. - if ((respData[6] & 0xff) > 0x06) { - isUltralightC = true; - } - } else { - // Fall back to ultralight - isUltralightC = false; - } - } - } - return isUltralightC; - } - - @Override - public Bundle[] getTechExtras() { - synchronized (this) { - if (mTechExtras != null) return mTechExtras; - mTechExtras = new Bundle[mTechList.length]; - for (int i = 0; i < mTechList.length; i++) { - Bundle extras = new Bundle(); - switch (mTechList[i]) { - case TagTechnology.NFC_A: { - byte[] actBytes = mTechActBytes[i]; - if ((actBytes != null) && (actBytes.length > 0)) { - extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); - } else { - // Unfortunately Jewel doesn't have act bytes, - // ignore this case. - } - extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); - break; - } - - case TagTechnology.NFC_B: { - // What's returned from the PN544 is actually: - // 4 bytes app data - // 3 bytes prot info - byte[] appData = new byte[4]; - byte[] protInfo = new byte[3]; - if (mTechPollBytes[i].length >= 7) { - System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); - System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); - - extras.putByteArray(NfcB.EXTRA_APPDATA, appData); - extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); - } - break; - } - - case TagTechnology.NFC_F: { - byte[] pmm = new byte[8]; - byte[] sc = new byte[2]; - if (mTechPollBytes[i].length >= 8) { - // At least pmm is present - System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); - extras.putByteArray(NfcF.EXTRA_PMM, pmm); - } - if (mTechPollBytes[i].length == 10) { - System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); - extras.putByteArray(NfcF.EXTRA_SC, sc); - } - break; - } - - case TagTechnology.ISO_DEP: { - if (hasTech(TagTechnology.NFC_A)) { - extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); - } - else { - extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); - } - break; - } - - case TagTechnology.NFC_V: { - // First byte response flags, second byte DSFID - if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { - extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); - extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); - } - break; - } - - case TagTechnology.MIFARE_ULTRALIGHT: { - boolean isUlc = isUltralightC(); - extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); - break; - } - - default: { - // Leave the entry in the array null - continue; - } - } - mTechExtras[i] = extras; - } - return mTechExtras; - } - } - - @Override - public NdefMessage findAndReadNdef() { - // Try to find NDEF on any of the technologies. - int[] technologies = getTechList(); - int[] handles = mTechHandles; - NdefMessage ndefMsg = null; - boolean foundFormattable = false; - int formattableHandle = 0; - int formattableLibNfcType = 0; - int status; - - for (int techIndex = 0; techIndex < technologies.length; techIndex++) { - // have we seen this handle before? - for (int i = 0; i < techIndex; i++) { - if (handles[i] == handles[techIndex]) { - continue; // don't check duplicate handles - } - } - - status = connectWithStatus(technologies[techIndex]); - if (status != 0) { - Log.d(TAG, "Connect Failed - status = "+ status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - // Check if this type is NDEF formatable - if (!foundFormattable) { - if (isNdefFormatable()) { - foundFormattable = true; - formattableHandle = getConnectedHandle(); - formattableLibNfcType = getConnectedLibNfcType(); - // We'll only add formattable tech if no ndef is - // found - this is because libNFC refuses to format - // an already NDEF formatted tag. - } - reconnect(); - } - - int[] ndefinfo = new int[2]; - status = checkNdefWithStatus(ndefinfo); - if (status != 0) { - Log.d(TAG, "Check NDEF Failed - status = " + status); - if (status == STATUS_CODE_TARGET_LOST) { - break; - } - continue; // try next handle - } - - // found our NDEF handle - boolean generateEmptyNdef = false; - - int supportedNdefLength = ndefinfo[0]; - int cardState = ndefinfo[1]; - byte[] buff = readNdef(); - if (buff != null) { - try { - ndefMsg = new NdefMessage(buff); - addNdefTechnology(ndefMsg, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } catch (FormatException e) { - // Create an intent anyway, without NDEF messages - generateEmptyNdef = true; - } - } else { - generateEmptyNdef = true; - } - - if (generateEmptyNdef) { - ndefMsg = null; - addNdefTechnology(null, - getConnectedHandle(), - getConnectedLibNfcType(), - getConnectedTechnology(), - supportedNdefLength, cardState); - reconnect(); - } - break; - } - - if (ndefMsg == null && foundFormattable) { - // Tag is not NDEF yet, and found a formattable target, - // so add formattable tech to tech list. - addNdefFormatableTechnology( - formattableHandle, - formattableLibNfcType); - } - - return ndefMsg; - } -} diff --git a/src/com/android/nfc/nxp/NativeP2pDevice.java b/src/com/android/nfc/nxp/NativeP2pDevice.java deleted file mode 100755 index 7c7db41..0000000 --- a/src/com/android/nfc/nxp/NativeP2pDevice.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.nfc.nxp; - -import com.android.nfc.DeviceHost.NfcDepEndpoint; - -/** - * Native interface to the P2P Initiator functions - */ -public class NativeP2pDevice implements NfcDepEndpoint { - - private int mHandle; - - private int mMode; - - private byte[] mGeneralBytes; - - private native byte[] doReceive(); - @Override - public byte[] receive() { - return doReceive(); - } - - private native boolean doSend(byte[] data); - @Override - public boolean send(byte[] data) { - return doSend(data); - } - - private native boolean doConnect(); - @Override - public boolean connect() { - return doConnect(); - } - - private native boolean doDisconnect(); - @Override - public boolean disconnect() { - return doDisconnect(); - } - - public native byte[] doTransceive(byte[] data); - @Override - public byte[] transceive(byte[] data) { - return doTransceive(data); - } - - @Override - public int getHandle() { - return mHandle; - } - - @Override - public int getMode() { - return mMode; - } - - @Override - public byte[] getGeneralBytes() { - return mGeneralBytes; - } - -} -- cgit v1.1 From 721d01960285314178c9026f4cbca449a5f385a6 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 11 Jul 2012 12:24:11 -0700 Subject: Implement connection handover LLCP service. (DO NOT MERGE) The Connection Handover specification dictates that we should exchange Hr/Hs records over a dedicated LLCP service. This adds the service, and starts using it by default. It will fall back to the SNEP GET method to remain compatible with Android 4.1 devices. SNEP GET on these devices will return "Not Implemented", also per the SNEP spec. Also fixed a bug in endianness of the OOB record. Bug: 6759842 Change-Id: Ifd360f556bf0e1757eb8bbaadf11efa094aefcf6 --- src/com/android/nfc/P2pLinkManager.java | 36 +++- .../android/nfc/handover/BluetoothOppHandover.java | 18 +- .../nfc/handover/ConfirmConnectActivity.java | 16 ++ src/com/android/nfc/handover/HandoverClient.java | 104 +++++++++ src/com/android/nfc/handover/HandoverManager.java | 8 +- src/com/android/nfc/handover/HandoverServer.java | 239 +++++++++++++++++++++ 6 files changed, 414 insertions(+), 7 deletions(-) create mode 100644 src/com/android/nfc/handover/HandoverClient.java create mode 100644 src/com/android/nfc/handover/HandoverServer.java diff --git a/src/com/android/nfc/P2pLinkManager.java b/src/com/android/nfc/P2pLinkManager.java index 189b560..253ddaf 100755 --- a/src/com/android/nfc/P2pLinkManager.java +++ b/src/com/android/nfc/P2pLinkManager.java @@ -17,7 +17,9 @@ package com.android.nfc; import com.android.nfc.echoserver.EchoServer; +import com.android.nfc.handover.HandoverClient; import com.android.nfc.handover.HandoverManager; +import com.android.nfc.handover.HandoverServer; import com.android.nfc.ndefpush.NdefPushClient; import com.android.nfc.ndefpush.NdefPushServer; import com.android.nfc.snep.SnepClient; @@ -123,6 +125,7 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba // TODO dynamically assign SAP values static final int NDEFPUSH_SAP = 0x10; + static final int HANDOVER_SAP = 0x14; static final int LINK_DEBOUNCE_MS = 750; @@ -155,6 +158,7 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba final NdefPushServer mNdefPushServer; final SnepServer mDefaultSnepServer; + final HandoverServer mHandoverServer; final EchoServer mEchoServer; final ActivityManager mActivityManager; final PackageManager mPackageManager; @@ -178,6 +182,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba public P2pLinkManager(Context context, HandoverManager handoverManager) { mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); mDefaultSnepServer = new SnepServer(mDefaultSnepCallback); + mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback); + if (ECHOSERVER_ENABLED) { mEchoServer = new EchoServer(); } else { @@ -206,12 +212,14 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba if (!mIsReceiveEnabled && receiveEnable) { mDefaultSnepServer.start(); mNdefPushServer.start(); + mHandoverServer.start(); if (mEchoServer != null) { mHandler.sendEmptyMessage(MSG_START_ECHOSERVER); } } else if (mIsReceiveEnabled && !receiveEnable) { mDefaultSnepServer.stop(); mNdefPushServer.stop(); + mHandoverServer.stop(); if (mEchoServer != null) { mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER); } @@ -465,11 +473,20 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba try { if (uris != null) { + HandoverClient handoverClient = new HandoverClient(); + NdefMessage response = null; NdefMessage request = handoverManager.createHandoverRequestMessage(); if (request != null) { - SnepMessage snepResponse = snepClient.get(request); - response = snepResponse.getNdefMessage(); + response = handoverClient.sendHandoverRequest(request); + + if (response == null) { + // Remote device may not support handover service, + // try the (deprecated) SNEP GET implementation + // for devices running Android 4.1 + SnepMessage snepResponse = snepClient.get(request); + response = snepResponse.getNdefMessage(); + } } // else, handover not supported if (response != null) { handoverManager.doHandoverUri(uris, response); @@ -495,6 +512,13 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba return SNEP_FAILURE; } + final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { + @Override + public void onHandoverRequestReceived() { + onReceiveHandover(); + } + }; + final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { @Override public void onMessageReceived(NdefMessage msg) { @@ -511,13 +535,17 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba @Override public SnepMessage doGet(int acceptableLength, NdefMessage msg) { + // The NFC Forum Default SNEP server is not allowed to respond to + // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, + // since Android 4.1 used the NFC Forum default server to + // implement connection handover, we will support this + // until we can deprecate it. NdefMessage response = mHandoverManager.tryHandoverRequest(msg); - if (response != null) { onReceiveHandover(); return SnepMessage.getSuccessResponse(response); } else { - return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_FOUND); + return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); } } }; diff --git a/src/com/android/nfc/handover/BluetoothOppHandover.java b/src/com/android/nfc/handover/BluetoothOppHandover.java index ece6a7b..ceb3c62 100644 --- a/src/com/android/nfc/handover/BluetoothOppHandover.java +++ b/src/com/android/nfc/handover/BluetoothOppHandover.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.nfc.handover; import android.bluetooth.BluetoothAdapter; @@ -33,7 +49,7 @@ public class BluetoothOppHandover implements Handler.Callback { static final int MSG_START_SEND = 0; - static final int REMOTE_BT_ENABLE_DELAY_MS = 3000; + static final int REMOTE_BT_ENABLE_DELAY_MS = 5000; static final String ACTION_HANDOVER_SEND = "android.btopp.intent.action.HANDOVER_SEND"; diff --git a/src/com/android/nfc/handover/ConfirmConnectActivity.java b/src/com/android/nfc/handover/ConfirmConnectActivity.java index 22d518f..35a7da1 100644 --- a/src/com/android/nfc/handover/ConfirmConnectActivity.java +++ b/src/com/android/nfc/handover/ConfirmConnectActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.nfc.handover; import android.app.Activity; diff --git a/src/com/android/nfc/handover/HandoverClient.java b/src/com/android/nfc/handover/HandoverClient.java new file mode 100644 index 0000000..86cd23b --- /dev/null +++ b/src/com/android/nfc/handover/HandoverClient.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.nfc.handover; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.util.Log; + +import com.android.nfc.LlcpException; +import com.android.nfc.NfcService; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +public final class HandoverClient { + private static final String TAG = "HandoverClient"; + private static final int MIU = 128; + // Max NDEF length to receive for Hr/Hs messages + private static final boolean DBG = false; + + public NdefMessage sendHandoverRequest(NdefMessage msg) { + if (msg == null) return null; + + NfcService service = NfcService.getInstance(); + + LlcpSocket sock = null; + int offset = 0; + byte[] buffer = msg.toByteArray(); + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + + try { + sock = service.createLlcpSocket(0, MIU, 1, 1024); + if (sock == null) { + throw new IOException("Could not connect to socket."); + } + if (DBG) Log.d(TAG, "about to connect to service " + + HandoverServer.HANDOVER_SERVICE_NAME); + sock.connectToService(HandoverServer.HANDOVER_SERVICE_NAME); + + int remoteMiu = sock.getRemoteMiu(); + if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message"); + while (offset < buffer.length) { + int length = Math.min(buffer.length - offset, remoteMiu); + byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length); + if (DBG) Log.d(TAG, "about to send a " + length + " byte packet"); + sock.send(tmpBuffer); + offset += length; + } + + // Now, try to read back the SNEP response + byte[] partial = new byte[sock.getLocalMiu()]; + NdefMessage handoverSelectMsg = null; + while (true) { + int size = sock.receive(partial); + if (size < 0) { + break; + } + byteStream.write(partial, 0, size); + try { + handoverSelectMsg = new NdefMessage(byteStream.toByteArray()); + // If we get here, message is complete + break; + } catch (FormatException e) { + // Ignore, and try to fetch more bytes + } + } + return handoverSelectMsg; + } catch (IOException e) { + if (DBG) Log.d(TAG, "couldn't connect to handover service"); + } catch (LlcpException e) { + if (DBG) Log.d(TAG, "couldn't connect to handover service"); + } finally { + if (sock != null) { + try { + if (DBG) Log.d(TAG, "about to close"); + sock.close(); + } catch (IOException e) { + // Ignore + } + } + try { + byteStream.close(); + } catch (IOException e) { + // Ignore + } + } + return null; + } +} diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index 9836cdc..51b123c 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -657,8 +657,12 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, NdefRecord createBluetoothOobDataRecord() { byte[] payload = new byte[8]; - payload[0] = 0; - payload[1] = (byte)payload.length; + // Note: this field should be little-endian per the BTSSP spec + // The Android 4.1 implementation used big-endian order here. + // No single Android implementation has ever interpreted this + // length field when parsing this record though. + payload[0] = (byte) (payload.length & 0xFF); + payload[1] = (byte) ((payload.length >> 8) & 0xFF); synchronized (HandoverManager.this) { if (mLocalBluetoothAddress == null) { diff --git a/src/com/android/nfc/handover/HandoverServer.java b/src/com/android/nfc/handover/HandoverServer.java new file mode 100644 index 0000000..e789387 --- /dev/null +++ b/src/com/android/nfc/handover/HandoverServer.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.nfc.handover; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.util.Log; + +import com.android.nfc.LlcpException; +import com.android.nfc.NfcService; +import com.android.nfc.DeviceHost.LlcpServerSocket; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +public final class HandoverServer { + public static final String HANDOVER_SERVICE_NAME = "urn:nfc:sn:handover"; + public static final String TAG = "HandoverServer"; + public static final Boolean DBG = false; + + public static final int MIU = 128; + + final HandoverManager mHandoverManager; + final int mSap; + final Callback mCallback; + + ServerThread mServerThread = null; + boolean mServerRunning = false; + + public interface Callback { + void onHandoverRequestReceived(); + } + + public HandoverServer(int sap, HandoverManager manager, Callback callback) { + mSap = sap; + mHandoverManager = manager; + mCallback = callback; + } + + public synchronized void start() { + if (mServerThread == null) { + mServerThread = new ServerThread(); + mServerThread.start(); + mServerRunning = true; + } + } + + public synchronized void stop() { + if (mServerThread != null) { + mServerThread.shutdown(); + mServerThread = null; + mServerRunning = false; + } + } + + private class ServerThread extends Thread { + private boolean mThreadRunning = true; + LlcpServerSocket mServerSocket; + + @Override + public void run() { + boolean threadRunning; + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + + while (threadRunning) { + try { + synchronized (HandoverServer.this) { + mServerSocket = NfcService.getInstance().createLlcpServerSocket(mSap, + HANDOVER_SERVICE_NAME, MIU, 1, 1024); + } + if (mServerSocket == null) { + if (DBG) Log.d(TAG, "failed to create LLCP service socket"); + return; + } + if (DBG) Log.d(TAG, "created LLCP service socket"); + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + + while (threadRunning) { + LlcpServerSocket serverSocket; + synchronized (HandoverServer.this) { + serverSocket = mServerSocket; + } + + if (serverSocket == null) { + if (DBG) Log.d(TAG, "Server socket shut down."); + return; + } + if (DBG) Log.d(TAG, "about to accept"); + LlcpSocket communicationSocket = serverSocket.accept(); + if (DBG) Log.d(TAG, "accept returned " + communicationSocket); + if (communicationSocket != null) { + new ConnectionThread(communicationSocket).start(); + } + + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + } + if (DBG) Log.d(TAG, "stop running"); + } catch (LlcpException e) { + Log.e(TAG, "llcp error", e); + } catch (IOException e) { + Log.e(TAG, "IO error", e); + } finally { + synchronized (HandoverServer.this) { + if (mServerSocket != null) { + if (DBG) Log.d(TAG, "about to close"); + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; + } + } + } + + synchronized (HandoverServer.this) { + threadRunning = mThreadRunning; + } + } + } + + public void shutdown() { + synchronized (HandoverServer.this) { + mThreadRunning = false; + if (mServerSocket != null) { + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; + } + } + } + } + + private class ConnectionThread extends Thread { + private final LlcpSocket mSock; + + ConnectionThread(LlcpSocket socket) { + super(TAG); + mSock = socket; + } + + @Override + public void run() { + if (DBG) Log.d(TAG, "starting connection thread"); + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + + try { + boolean running; + synchronized (HandoverServer.this) { + running = mServerRunning; + } + + byte[] partial = new byte[mSock.getLocalMiu()]; + + NdefMessage handoverRequestMsg = null; + while (running) { + int size = mSock.receive(partial); + if (size < 0) { + break; + } + byteStream.write(partial, 0, size); + // 1) Try to parse a handover request message from bytes received so far + try { + handoverRequestMsg = new NdefMessage(byteStream.toByteArray()); + } catch (FormatException e) { + // Ignore, and try to fetch more bytes + } + + if (handoverRequestMsg != null) { + // 2) convert to handover response + NdefMessage resp = mHandoverManager.tryHandoverRequest(handoverRequestMsg); + if (resp == null) { + Log.e(TAG, "Failed to create handover response"); + break; + } + + // 3) send handover response + int offset = 0; + byte[] buffer = resp.toByteArray(); + int remoteMiu = mSock.getRemoteMiu(); + while (offset < buffer.length) { + int length = Math.min(buffer.length - offset, remoteMiu); + byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length); + mSock.send(tmpBuffer); + offset += length; + } + // We're done + mCallback.onHandoverRequestReceived(); + break; + } + + synchronized (HandoverServer.this) { + running = mServerRunning; + } + } + + } catch (IOException e) { + if (DBG) Log.d(TAG, "IOException"); + } finally { + try { + if (DBG) Log.d(TAG, "about to close"); + mSock.close(); + } catch (IOException e) { + // ignore + } + try { + byteStream.close(); + } catch (IOException e) { + // ignore + } + } + if (DBG) Log.d(TAG, "finished connection thread"); + } + } +} -- cgit v1.1 From 25b0c5d26d58d7d0af200b315a840881001b544d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 23 Jul 2012 09:44:37 -0700 Subject: Fix type of collision resolution record. (DO NOT MERGE) Bug: 6759842 Change-Id: I6d1e24472702007616c0be71aacda9e591a23620 --- src/com/android/nfc/handover/HandoverManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index 51b123c..f77f780 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -71,6 +71,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, static final byte[] TYPE_BT_OOB = "application/vnd.bluetooth.ep.oob". getBytes(Charset.forName("US_ASCII")); + static final byte[] RTD_COLLISION_RESOLUTION = {0x63, 0x72}; // "cr"; + static final String ACTION_BT_OPP_TRANSFER_PROGRESS = "android.btopp.intent.action.BT_OPP_TRANSFER_PROGRESS"; @@ -642,7 +644,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, static NdefRecord createCollisionRecord() { byte[] random = new byte[2]; new Random().nextBytes(random); - return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_HANDOVER_REQUEST, null, random); + return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, RTD_COLLISION_RESOLUTION, null, random); } NdefRecord createBluetoothAlternateCarrierRecord(boolean activating) { -- cgit v1.1 From 96c08a7d49a8dcd33a5acac1c7c73fe3711bd9bd Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 25 Jul 2012 13:30:11 -0700 Subject: Point jni class references to new dhimpl package. (DO NOT MERGE) The DeviceHost classed moved to a new package, updated the JNI references accordingly. Change-Id: I11d30b241f80e2efba4570a921346ea3689b4ec5 --- ..._android_nfc_NativeLlcpConnectionlessSocket.cpp | 2 +- .../com_android_nfc_NativeLlcpServiceSocket.cpp | 6 +++--- nxp/jni/com_android_nfc_NativeLlcpSocket.cpp | 2 +- nxp/jni/com_android_nfc_NativeNfcManager.cpp | 24 +++++++++++----------- nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp | 2 +- nxp/jni/com_android_nfc_NativeNfcTag.cpp | 2 +- nxp/jni/com_android_nfc_NativeP2pDevice.cpp | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp index 188edb4..86607b5 100644 --- a/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp +++ b/nxp/jni/com_android_nfc_NativeLlcpConnectionlessSocket.cpp @@ -246,7 +246,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpConnectionlessSocket", + "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp index 92de3e4..2fccfc9 100644 --- a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp +++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp @@ -139,7 +139,7 @@ static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint m } /* Create new LlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1) { ALOGD("LLCP Socket creation error"); goto clean_and_return; @@ -209,7 +209,7 @@ static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) */ static JNINativeMethod gMethods[] = { - {"doAccept", "(III)Lcom/android/nfc/nxp/NativeLlcpSocket;", + {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void *)com_NativeLlcpServiceSocket_doAccept}, {"doClose", "()Z", @@ -220,7 +220,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpServiceSocket", + "com/android/nfc/dhimpl/NativeLlcpServiceSocket", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp index 0c0b830..91a72a5 100644 --- a/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp +++ b/nxp/jni/com_android_nfc_NativeLlcpSocket.cpp @@ -462,7 +462,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods)); + "com/android/nfc/dhimpl/NativeLlcpSocket",gMethods, NELEM(gMethods)); } } // namespace android diff --git a/nxp/jni/com_android_nfc_NativeNfcManager.cpp b/nxp/jni/com_android_nfc_NativeNfcManager.cpp index 704ee6a..91bc06b 100644 --- a/nxp/jni/com_android_nfc_NativeNfcManager.cpp +++ b/nxp/jni/com_android_nfc_NativeNfcManager.cpp @@ -1643,16 +1643,16 @@ static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject /* Initialize native cached references */ cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, - "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); + "notifyNdefMessageListeners","(Lcom/android/nfc/dhimpl/NativeNfcTag;)V"); cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, "notifyTransactionListeners", "([B)V"); cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, - "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + "notifyLlcpLinkActivation","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, - "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); + "notifyLlcpLinkDeactivated","(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, "notifyTargetDeselected","()V"); @@ -1672,13 +1672,13 @@ static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, "notifySeEmvCardRemoval", "()V"); - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeNfcTag",&(nat->cached_NfcTag)) == -1) { ALOGD("Native Structure initialization failed"); return FALSE; } - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) { ALOGD("Native Structure initialization failed"); return FALSE; @@ -2104,7 +2104,7 @@ static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEn /* Create new NativeLlcpConnectionlessSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) { goto error; } @@ -2231,7 +2231,7 @@ static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, j TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpServiceSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpServiceSocket",&(serviceSocket)) == -1) { ALOGE("Llcp Socket object creation error"); goto error; @@ -2315,7 +2315,7 @@ static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpSocket object */ - if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) + if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1) { ALOGE("Llcp socket object creation error"); return NULL; @@ -2565,13 +2565,13 @@ static JNINativeMethod gMethods[] = {"doActivateLlcp", "()Z", (void *)com_android_nfc_NfcManager_doActivateLlcp}, - {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, - {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, - {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, {"doGetLastError", "()I", @@ -2615,7 +2615,7 @@ int register_com_android_nfc_NativeNfcManager(JNIEnv *e) } return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcManager", + "com/android/nfc/dhimpl/NativeNfcManager", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp index bf0bffc..bb1bb2a 100755 --- a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp +++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp @@ -763,7 +763,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcSecureElement", + "com/android/nfc/dhimpl/NativeNfcSecureElement", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp index dbf8dc9..a621d2a 100644 --- a/nxp/jni/com_android_nfc_NativeNfcTag.cpp +++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp @@ -1248,7 +1248,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeNfcTag(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeNfcTag", + "com/android/nfc/dhimpl/NativeNfcTag", gMethods, NELEM(gMethods)); } diff --git a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp index b3cc6e3..fa46052 100644 --- a/nxp/jni/com_android_nfc_NativeP2pDevice.cpp +++ b/nxp/jni/com_android_nfc_NativeP2pDevice.cpp @@ -483,7 +483,7 @@ static JNINativeMethod gMethods[] = int register_com_android_nfc_NativeP2pDevice(JNIEnv *e) { return jniRegisterNativeMethods(e, - "com/android/nfc/nxp/NativeP2pDevice", + "com/android/nfc/dhimpl/NativeP2pDevice", gMethods, NELEM(gMethods)); } -- cgit v1.1 From a3f98c286444a9fb009cf6c6753ae67bdf51ac6b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 25 Jul 2012 15:07:43 -0700 Subject: NFC: Initial NCI DeviceHost and JNI implementation. (DO NOT MERGE) From partner drop at 07/20. Modified to fit into our new JNI/DH split. New build config that builds two targets, Nfc and NfcNci, each with their own dependencies. Product config files have to specify either Nfc or NfcNci in their packages config. Change-Id: I348a3aad7167195ca03baf9636408ab8e4c55fce --- Android.mk | 35 +- nci/Android.mk | 3 + nci/jni/Android.mk | 47 + nci/jni/CondVar.cpp | 136 ++ nci/jni/CondVar.h | 82 + nci/jni/DataQueue.cpp | 146 ++ nci/jni/DataQueue.h | 97 + nci/jni/HostAidRouter.cpp | 281 +++ nci/jni/HostAidRouter.h | 147 ++ nci/jni/IntervalTimer.cpp | 90 + nci/jni/IntervalTimer.h | 29 + nci/jni/Mutex.cpp | 127 ++ nci/jni/Mutex.h | 93 + nci/jni/NativeLlcpConnectionlessSocket.cpp | 313 +++ nci/jni/NativeLlcpServiceSocket.cpp | 162 ++ nci/jni/NativeLlcpSocket.cpp | 274 +++ nci/jni/NativeNfcManager.cpp | 1686 +++++++++++++++ nci/jni/NativeNfcTag.cpp | 1554 ++++++++++++++ nci/jni/NativeP2pDevice.cpp | 95 + nci/jni/NativeSecureElement.cpp | 221 ++ nci/jni/NfcJniUtil.cpp | 151 ++ nci/jni/NfcJniUtil.h | 159 ++ nci/jni/NfcTag.cpp | 1229 +++++++++++ nci/jni/NfcTag.h | 357 ++++ nci/jni/PeerToPeer.cpp | 2158 ++++++++++++++++++++ nci/jni/PeerToPeer.h | 705 +++++++ nci/jni/PowerSwitch.cpp | 410 ++++ nci/jni/PowerSwitch.h | 236 +++ nci/jni/RouteDataSet.cpp | 546 +++++ nci/jni/RouteDataSet.h | 299 +++ nci/jni/SecureElement.cpp | 1987 ++++++++++++++++++ nci/jni/SecureElement.h | 560 +++++ nci/jni/SyncEvent.h | 167 ++ .../nfc/dhimpl/NativeLlcpConnectionlessSocket.java | 78 + .../nfc/dhimpl/NativeLlcpServiceSocket.java | 53 + .../com/android/nfc/dhimpl/NativeLlcpSocket.java | 99 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 385 ++++ .../android/nfc/dhimpl/NativeNfcSecureElement.java | 67 + nci/src/com/android/nfc/dhimpl/NativeNfcTag.java | 811 ++++++++ .../com/android/nfc/dhimpl/NativeP2pDevice.java | 77 + .../com/android/nfc/dhimpl/NativeNfcManager.java | 22 + src/com/android/nfc/DeviceHost.java | 4 + src/com/android/nfc/NfcService.java | 24 +- 43 files changed, 16179 insertions(+), 23 deletions(-) create mode 100644 nci/Android.mk create mode 100644 nci/jni/Android.mk create mode 100644 nci/jni/CondVar.cpp create mode 100644 nci/jni/CondVar.h create mode 100644 nci/jni/DataQueue.cpp create mode 100644 nci/jni/DataQueue.h create mode 100644 nci/jni/HostAidRouter.cpp create mode 100644 nci/jni/HostAidRouter.h create mode 100644 nci/jni/IntervalTimer.cpp create mode 100644 nci/jni/IntervalTimer.h create mode 100644 nci/jni/Mutex.cpp create mode 100644 nci/jni/Mutex.h create mode 100644 nci/jni/NativeLlcpConnectionlessSocket.cpp create mode 100644 nci/jni/NativeLlcpServiceSocket.cpp create mode 100644 nci/jni/NativeLlcpSocket.cpp create mode 100755 nci/jni/NativeNfcManager.cpp create mode 100755 nci/jni/NativeNfcTag.cpp create mode 100644 nci/jni/NativeP2pDevice.cpp create mode 100755 nci/jni/NativeSecureElement.cpp create mode 100755 nci/jni/NfcJniUtil.cpp create mode 100755 nci/jni/NfcJniUtil.h create mode 100755 nci/jni/NfcTag.cpp create mode 100755 nci/jni/NfcTag.h create mode 100644 nci/jni/PeerToPeer.cpp create mode 100644 nci/jni/PeerToPeer.h create mode 100755 nci/jni/PowerSwitch.cpp create mode 100755 nci/jni/PowerSwitch.h create mode 100644 nci/jni/RouteDataSet.cpp create mode 100644 nci/jni/RouteDataSet.h create mode 100755 nci/jni/SecureElement.cpp create mode 100755 nci/jni/SecureElement.h create mode 100644 nci/jni/SyncEvent.h create mode 100755 nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeNfcManager.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeNfcTag.java create mode 100755 nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java diff --git a/Android.mk b/Android.mk index 2cdfc68..9aa7ee2 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,8 @@ LOCAL_PATH:= $(call my-dir) + +######################################## +# NXP Configuration +######################################## include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional @@ -6,13 +10,8 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) -ifeq ($(NFC_USE_NCI_STACK), true) - LOCAL_SRC_FILES += \ - $(call all-java-files-under, nci) -else - LOCAL_SRC_FILES += \ +LOCAL_SRC_FILES += \ $(call all-java-files-under, nxp) -endif LOCAL_PACKAGE_NAME := Nfc LOCAL_CERTIFICATE := platform @@ -25,6 +24,30 @@ LOCAL_PROGUARD_ENABLED := disabled include $(BUILD_PACKAGE) +######################################## +# NCI Configuration +######################################## +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) + +LOCAL_SRC_FILES += \ + $(call all-java-files-under, nci) + +LOCAL_PACKAGE_NAME := NfcNci +LOCAL_OVERRIDES_PACKAGES := Nfc +LOCAL_CERTIFICATE := platform + +LOCAL_STATIC_JAVA_LIBRARIES := NfcLogTags + +LOCAL_JNI_SHARED_LIBRARIES := libnfc_nci_jni + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) ##### # static lib for the log tags diff --git a/nci/Android.mk b/nci/Android.mk new file mode 100644 index 0000000..34f4385 --- /dev/null +++ b/nci/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH:= $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk new file mode 100644 index 0000000..a1fb83e --- /dev/null +++ b/nci/jni/Android.mk @@ -0,0 +1,47 @@ +VOB_COMPONENTS := external/libnfc-nci/src +NFA := $(VOB_COMPONENTS)/nfa +NFC := $(VOB_COMPONENTS)/nfc + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false + +ifneq ($(NCI_VERSION),) +LOCAL_CFLAGS += -DNCI_VERSION=$(NCI_VERSION) -O0 -g +endif + +define all-cpp-files-under +$(patsubst ./%,%, \ + $(shell cd $(LOCAL_PATH) ; \ + find $(1) -name "*.cpp" -and -not -name ".*") \ + ) +endef + +LOCAL_SRC_FILES:= $(call all-cpp-files-under, .) + +LOCAL_C_INCLUDES += \ + external/astl/include \ + external/libxml2/include \ + external/icu4c/common \ + $(NFA)/include \ + $(NFA)/brcm \ + $(NFC)/include \ + $(NFC)/brcm \ + $(NFC)/int \ + $(VOB_COMPONENTS)/include \ + $(VOB_COMPONENTS)/gki/ulinux \ + $(VOB_COMPONENTS)/gki/common + +LOCAL_SHARED_LIBRARIES := \ + libicuuc \ + libnativehelper \ + libcutils \ + libutils \ + libnfc-nci + +LOCAL_STATIC_LIBRARIES := libxml2 + +LOCAL_MODULE := libnfc_nci_jni +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/nci/jni/CondVar.cpp b/nci/jni/CondVar.cpp new file mode 100644 index 0000000..cb67825 --- /dev/null +++ b/nci/jni/CondVar.cpp @@ -0,0 +1,136 @@ +/***************************************************************************** +** +** Name: CondVar.cpp +** +** Description: Encapsulate a condition variable for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "CondVar.h" +#include "NfcJniUtil.h" +#include + + +/******************************************************************************* +** +** Function: CondVar +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +CondVar::CondVar () +{ + memset (&mCondition, 0, sizeof(mCondition)); + int const res = pthread_cond_init (&mCondition, NULL); + if (res) + { + ALOGE ("CondVar::CondVar: fail init; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: ~CondVar +** +** Description: Cleanup all resources. +** +** Returns: None. +** +*******************************************************************************/ +CondVar::~CondVar () +{ + int const res = pthread_cond_destroy (&mCondition); + if (res) + { + ALOGE ("CondVar::~CondVar: fail destroy; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: wait +** +** Description: Block the caller and wait for a condition. +** +** Returns: None. +** +*******************************************************************************/ +void CondVar::wait (Mutex& mutex) +{ + int const res = pthread_cond_wait (&mCondition, mutex.nativeHandle()); + if (res) + { + ALOGE ("CondVar::wait: fail wait; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: wait +** +** Description: Block the caller and wait for a condition. +** millisec: Timeout in milliseconds. +** +** Returns: True if wait is successful; false if timeout occurs. +** +*******************************************************************************/ +bool CondVar::wait (Mutex& mutex, long millisec) +{ + bool retVal = false; + struct timespec absoluteTime; + + if (clock_gettime (CLOCK_MONOTONIC, &absoluteTime) == -1) + { + ALOGE ("CondVar::wait: fail get time; errno=0x%X", errno); + } + else + { + absoluteTime.tv_sec += millisec / 1000; + long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000); + if (ns > 1000000000) + { + absoluteTime.tv_sec++; + absoluteTime.tv_nsec = ns - 1000000000; + } + else + absoluteTime.tv_nsec = ns; + } + + //pthread_cond_timedwait_monotonic_np() is an Android-specific function + //declared in /development/ndk/platforms/android-9/include/pthread.h; + //it uses monotonic clock. + //the standard pthread_cond_timedwait() uses realtime clock. + int waitResult = pthread_cond_timedwait_monotonic_np (&mCondition, mutex.nativeHandle(), &absoluteTime); + if ((waitResult != 0) && (waitResult != ETIMEDOUT)) + ALOGE ("CondVar::wait: fail timed wait; error=0x%X", waitResult); + retVal = (waitResult == 0); //waited successfully + return retVal; +} + + +/******************************************************************************* +** +** Function: notifyOne +** +** Description: Unblock the waiting thread. +** +** Returns: None. +** +*******************************************************************************/ +void CondVar::notifyOne () +{ + int const res = pthread_cond_signal (&mCondition); + if (res) + { + ALOGE ("CondVar::notifyOne: fail signal; error=0x%X", res); + } +} + diff --git a/nci/jni/CondVar.h b/nci/jni/CondVar.h new file mode 100644 index 0000000..bfe4dfb --- /dev/null +++ b/nci/jni/CondVar.h @@ -0,0 +1,82 @@ +/***************************************************************************** +** +** Name: CondVar.h +** +** Description: Encapsulate a condition variable for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include +#include "Mutex.h" + + +class CondVar +{ +public: + /******************************************************************************* + ** + ** Function: CondVar + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + CondVar (); + + + /******************************************************************************* + ** + ** Function: ~CondVar + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~CondVar (); + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the caller and wait for a condition. + ** + ** Returns: None. + ** + *******************************************************************************/ + void wait (Mutex& mutex); + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the caller and wait for a condition. + ** millisec: Timeout in milliseconds. + ** + ** Returns: True if wait is successful; false if timeout occurs. + ** + *******************************************************************************/ + bool wait (Mutex& mutex, long millisec); + + + /******************************************************************************* + ** + ** Function: notifyOne + ** + ** Description: Unblock the waiting thread. + ** + ** Returns: None. + ** + *******************************************************************************/ + void notifyOne (); + +private: + pthread_cond_t mCondition; +}; \ No newline at end of file diff --git a/nci/jni/DataQueue.cpp b/nci/jni/DataQueue.cpp new file mode 100644 index 0000000..2b07c7e --- /dev/null +++ b/nci/jni/DataQueue.cpp @@ -0,0 +1,146 @@ +/***************************************************************************** +** +** Name: DataQueue.cpp +** +** Description: Store data bytes in a variable-size queue. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "DataQueue.h" + + +/******************************************************************************* +** +** Function: DataQueue +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +DataQueue::DataQueue () +{ +} + + +/******************************************************************************* +** +** Function: ~DataQueue +** +** Description: Release all resources. +** +** Returns: None. +** +*******************************************************************************/ +DataQueue::~DataQueue () +{ + mMutex.lock (); + while (mQueue.empty() == false) + { + tHeader* header = mQueue.front (); + mQueue.pop_front (); + free (header); + } + mMutex.unlock (); +} + + +bool DataQueue::isEmpty() +{ + mMutex.lock (); + bool retval = mQueue.empty(); + mMutex.unlock (); + return retval; +} + + +/******************************************************************************* +** +** Function: enqueue +** +** Description: Append data to the queue. +** data: array of bytes +** dataLen: length of the data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool DataQueue::enqueue (UINT8* data, UINT16 dataLen) +{ + if ((data == NULL) || (dataLen==0)) + return false; + + mMutex.lock (); + + bool retval = false; + tHeader* header = (tHeader*) malloc (sizeof(tHeader) + dataLen); + + if (header) + { + memset (header, 0, sizeof(tHeader)); + header->mDataLen = dataLen; + memcpy (header+1, data, dataLen); + + mQueue.push_back (header); + + retval = true; + } + else + { + ALOGE ("DataQueue::enqueue: out of memory ?????"); + } + mMutex.unlock (); + return retval; +} + + +/******************************************************************************* +** +** Function: dequeue +** +** Description: Retrieve and remove data from the front of the queue. +** buffer: array to store the data. +** bufferMaxLen: maximum size of the buffer. +** actualLen: actual length of the data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool DataQueue::dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen) +{ + mMutex.lock (); + + tHeader* header = mQueue.front (); + bool retval = false; + + if (header && buffer && (bufferMaxLen>0)) + { + if (header->mDataLen <= bufferMaxLen) + { + //caller's buffer is big enough to store all data + actualLen = header->mDataLen; + char* src = (char*)(header) + sizeof(tHeader) + header->mOffset; + memcpy (buffer, src, actualLen); + + mQueue.pop_front (); + free (header); + } + else + { + //caller's buffer is too small + actualLen = bufferMaxLen; + char* src = (char*)(header) + sizeof(tHeader) + header->mOffset; + memcpy (buffer, src, actualLen); + //adjust offset so the next dequeue() will get the remainder + header->mDataLen -= actualLen; + header->mOffset += actualLen; + } + retval = true; + } + mMutex.unlock (); + return retval; +} + diff --git a/nci/jni/DataQueue.h b/nci/jni/DataQueue.h new file mode 100644 index 0000000..4c0c454 --- /dev/null +++ b/nci/jni/DataQueue.h @@ -0,0 +1,97 @@ +/***************************************************************************** +** +** Name: DataQueue.h +** +** Description: Store data bytes in a variable-size queue. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include "NfcJniUtil.h" +#include "gki.h" +#include "Mutex.h" +#include + + +class DataQueue +{ +public: + /******************************************************************************* + ** + ** Function: DataQueue + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + DataQueue (); + + + /******************************************************************************* + ** + ** Function: ~DataQueue + ** + ** Description: Release all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~DataQueue (); + + + /******************************************************************************* + ** + ** Function: enqueue + ** + ** Description: Append data to the queue. + ** data: array of bytes + ** dataLen: length of the data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool enqueue (UINT8* data, UINT16 dataLen); + + + /******************************************************************************* + ** + ** Function: dequeue + ** + ** Description: Retrieve and remove data from the front of the queue. + ** buffer: array to store the data. + ** bufferMaxLen: maximum size of the buffer. + ** actualLen: actual length of the data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen); + + + /******************************************************************************* + ** + ** Function: isEmpty + ** + ** Description: Whether the queue is empty. + ** + ** Returns: True if empty. + ** + *******************************************************************************/ + bool isEmpty(); + +private: + struct tHeader + { + UINT16 mDataLen; //number of octets of data + UINT16 mOffset; //offset of the first octet of data + }; + typedef std::list Queue; + + Queue mQueue; + Mutex mMutex; +}; + diff --git a/nci/jni/HostAidRouter.cpp b/nci/jni/HostAidRouter.cpp new file mode 100644 index 0000000..dd54d19 --- /dev/null +++ b/nci/jni/HostAidRouter.cpp @@ -0,0 +1,281 @@ +/***************************************************************************** +** +** Name: HostAidRouter.cpp +** +** Description: Manage listen-mode AID routing to the host. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include "HostAidRouter.h" +#include "config.h" +#include "SecureElement.h" + + +HostAidRouter HostAidRouter::sHostAidRouter; //singleton HostAidRouter object + + +/******************************************************************************* +** +** Function: HostAidRouter +** +** Description: Private constructor to prevent public call. +** +** Returns: None. +** +*******************************************************************************/ +HostAidRouter::HostAidRouter () + : mTempHandle (NFA_HANDLE_INVALID), + mIsFeatureEnabled (true) +{ +} + + +/******************************************************************************* +** +** Function: ~HostAidRouter +** +** Description: Private destructor to prevent public call. +** +** Returns: None. +** +*******************************************************************************/ +HostAidRouter::~HostAidRouter () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Obtain a reference to the singleton object of HostAidRouter +** +** Returns: Reference to HostAidRouter object. +** +*******************************************************************************/ +HostAidRouter& HostAidRouter::getInstance () +{ + return sHostAidRouter; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize all resources. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::initialize () +{ + unsigned long num = 0; + mTempHandle = NFA_HANDLE_INVALID; + mHandleDatabase.clear (); + + if (GetNumValue (NAME_REGISTER_VIRTUAL_SE, &num, sizeof (num))) + mIsFeatureEnabled = num != 0; + return true; +} + + +/******************************************************************************* +** +** Function: addPpseRoute +** +** Description: Route Proximity Payment System Environment request +** to the host. This function is called when there is no +** route data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::addPpseRoute () +{ + static const char fn [] = "HostAidRouter::addPpseRoute"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsFeatureEnabled) + { + ALOGD ("%s: feature disabled", fn); + goto TheEnd; + } + + { + ALOGD ("%s: register PPSE AID", fn); + SyncEventGuard guard (mRegisterEvent); + mTempHandle = NFA_HANDLE_INVALID; + nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) "2PAY.SYS.DDF01", 14, stackCallback); + if (nfaStat == NFA_STATUS_OK) + { + mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT + if (mTempHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: received invalid handle", fn); + goto TheEnd; + } + else + mHandleDatabase.push_back (mTempHandle); + } + else + { + ALOGE ("%s: fail register", fn); + goto TheEnd; + } + } + retval = true; + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: deleteAllRoutes +** +** Description: Delete all AID routes to the host. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::deleteAllRoutes () +{ + static const char fn [] = "HostAidRouter::deleteAllRoutes"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsFeatureEnabled) + { + ALOGD ("%s: feature disabled", fn); + goto TheEnd; + } + + //deregister each registered AID from the stack + for (AidHandleDatabase::iterator iter1 = mHandleDatabase.begin(); iter1 != mHandleDatabase.end(); iter1++) + { + tNFA_HANDLE aidHandle = *iter1; + ALOGD ("%s: deregister h=0x%X", fn, aidHandle); + SyncEventGuard guard (mDeregisterEvent); + nfaStat = NFA_CeDeregisterAidOnDH (aidHandle); + if (nfaStat == NFA_STATUS_OK) + mDeregisterEvent.wait (); //wait for NFA_CE_DEREGISTERED_EVT + else + ALOGE ("%s: fail deregister", fn); + } + mHandleDatabase.clear (); + retval = true; + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: startRoute +** +** Description: Begin to route AID request to the host. +** aid: Buffer that contains Application ID +** aidLen: Actual length of the buffer. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool HostAidRouter::startRoute (const UINT8* aid, UINT8 aidLen) +{ + static const char fn [] = "HostAidRouter::startRoute"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsFeatureEnabled) + { + ALOGD ("%s: feature disabled", fn); + goto TheEnd; + } + + { + ALOGD ("%s: register AID; len=%u", fn, aidLen); + SyncEventGuard guard (mRegisterEvent); + mTempHandle = NFA_HANDLE_INVALID; + nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) aid, aidLen, stackCallback); + if (nfaStat == NFA_STATUS_OK) + { + mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT + if (mTempHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: received invalid handle", fn); + goto TheEnd; + } + else + mHandleDatabase.push_back (mTempHandle); + } + else + { + ALOGE ("%s: fail register", fn); + goto TheEnd; + } + } + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: stackCallback +** +** Description: Receive events from the NFC stack. +** +** Returns: None. +** +*******************************************************************************/ +void HostAidRouter::stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + static const char fn [] = "HostAidRouter::stackCallback"; + ALOGD("%s: event=0x%X", fn, event); + + switch (event) + { + case NFA_CE_REGISTERED_EVT: + { + tNFA_CE_REGISTERED& ce_registered = eventData->ce_registered; + ALOGD("%s: NFA_CE_REGISTERED_EVT; status=0x%X; h=0x%X", fn, ce_registered.status, ce_registered.handle); + SyncEventGuard guard (sHostAidRouter.mRegisterEvent); + if (ce_registered.status == NFA_STATUS_OK) + sHostAidRouter.mTempHandle = ce_registered.handle; + else + sHostAidRouter.mTempHandle = NFA_HANDLE_INVALID; + sHostAidRouter.mRegisterEvent.notifyOne(); + } + break; + + case NFA_CE_DEREGISTERED_EVT: + { + tNFA_CE_DEREGISTERED& ce_deregistered = eventData->ce_deregistered; + ALOGD("%s: NFA_CE_DEREGISTERED_EVT; h=0x%X", fn, ce_deregistered.handle); + SyncEventGuard guard (sHostAidRouter.mDeregisterEvent); + sHostAidRouter.mDeregisterEvent.notifyOne(); + } + break; + + case NFA_CE_DATA_EVT: + { + tNFA_CE_DATA& ce_data = eventData->ce_data; + ALOGD("%s: NFA_CE_DATA_EVT; h=0x%X; data len=%u", fn, ce_data.handle, ce_data.len); + SecureElement::getInstance().notifyTransactionListenersOfAid ((UINT8 *)"2PAY.SYS.DDF01", 14); + } + break; + } +} diff --git a/nci/jni/HostAidRouter.h b/nci/jni/HostAidRouter.h new file mode 100644 index 0000000..409df93 --- /dev/null +++ b/nci/jni/HostAidRouter.h @@ -0,0 +1,147 @@ +/***************************************************************************** +** +** Name: HostAidRouter.h +** +** Description: Manage listen-mode AID routing to the host. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "SyncEvent.h" +#include "NfcJniUtil.h" +#include "RouteDataSet.h" +#include +extern "C" +{ + #include "nfa_api.h" +} + + +class HostAidRouter +{ +public: + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Obtain a reference to the singleton object of HostAidRouter + ** + ** Returns: Reference to HostAidRouter object. + ** + *******************************************************************************/ + static HostAidRouter& getInstance (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize all resources. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool initialize (); + + + /******************************************************************************* + ** + ** Function: addPpseRoute + ** + ** Description: Route Proximity Payment System Environment request + ** to the host. This function is called when there is no + ** route data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool addPpseRoute (); + + + /******************************************************************************* + ** + ** Function: deleteAllRoutes + ** + ** Description: Delete all AID routes to the host. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool deleteAllRoutes (); + + + /******************************************************************************* + ** + ** Function: isFeatureEnabled + ** + ** Description: Is AID-routing-to-host feature enabled? + ** + ** Returns: True if enabled. + ** + *******************************************************************************/ + bool isFeatureEnabled () {return mIsFeatureEnabled;}; + + + /******************************************************************************* + ** + ** Function: startRoute + ** + ** Description: Begin to route AID request to the host. + ** aid: Buffer that contains Application ID + ** aidLen: Actual length of the buffer. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool startRoute (const UINT8* aid, UINT8 aidLen); + + +private: + typedef std::vector AidHandleDatabase; + + tNFA_HANDLE mTempHandle; + bool mIsFeatureEnabled; + static HostAidRouter sHostAidRouter; //singleton object + RouteDataSet mRouteDataSet; //route data from xml file + SyncEvent mRegisterEvent; + SyncEvent mDeregisterEvent; + AidHandleDatabase mHandleDatabase; //store all AID handles that are registered with the stack + + + /******************************************************************************* + ** + ** Function: HostAidRouter + ** + ** Description: Private constructor to prevent public call. + ** + ** Returns: None. + ** + *******************************************************************************/ + HostAidRouter (); + + + /******************************************************************************* + ** + ** Function: ~HostAidRouter + ** + ** Description: Private destructor to prevent public call. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~HostAidRouter (); + + + /******************************************************************************* + ** + ** Function: stackCallback + ** + ** Description: Receive events from the NFC stack. + ** + ** Returns: None. + ** + *******************************************************************************/ + static void stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventdata); +}; diff --git a/nci/jni/IntervalTimer.cpp b/nci/jni/IntervalTimer.cpp new file mode 100644 index 0000000..4cca01a --- /dev/null +++ b/nci/jni/IntervalTimer.cpp @@ -0,0 +1,90 @@ +/***************************************************************************** +** +** Name: IntervalTimer.cpp +** +** Description: Asynchronous interval timer. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "IntervalTimer.h" +#include + + +IntervalTimer::IntervalTimer() +{ + mTimerId = NULL; + mCb = NULL; +} + + +bool IntervalTimer::set(int ms, TIMER_FUNC cb) +{ + if (mTimerId == NULL) + { + if (cb == NULL) + return false; + + if (!create(cb)) + return false; + } + if (cb != mCb) + { + kill(); + if (!create(cb)) + return false; + } + + int stat = 0; + struct itimerspec ts; + ts.it_value.tv_sec = ms / 1000; + ts.it_value.tv_nsec = (ms % 1000) * 1000000; + + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + stat = timer_settime(mTimerId, 0, &ts, 0); + if (stat == -1) + ALOGE("IntervalTimer::set: fail set timer"); + return stat == 0; +} + + +IntervalTimer::~IntervalTimer() +{ + kill(); +} + + +void IntervalTimer::kill() +{ + if (mTimerId == NULL) + return; + + timer_delete(mTimerId); + mTimerId = NULL; + mCb = NULL; +} + + +bool IntervalTimer::create(TIMER_FUNC cb) +{ + struct sigevent se; + int stat = 0; + + /* + * Set the sigevent structure to cause the signal to be + * delivered by creating a new thread. + */ + se.sigev_notify = SIGEV_THREAD; + se.sigev_value.sival_ptr = &mTimerId; + se.sigev_notify_function = cb; + se.sigev_notify_attributes = NULL; + mCb = cb; + stat = timer_create(CLOCK_MONOTONIC, &se, &mTimerId); + if (stat == -1) + ALOGE("IntervalTimer::create: fail create timer"); + return stat == 0; +} diff --git a/nci/jni/IntervalTimer.h b/nci/jni/IntervalTimer.h new file mode 100644 index 0000000..0f1095f --- /dev/null +++ b/nci/jni/IntervalTimer.h @@ -0,0 +1,29 @@ +/***************************************************************************** +** +** Name: IntervalTimer.h +** +** Description: Asynchronous interval timer. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include + + +class IntervalTimer +{ +public: + typedef void (*TIMER_FUNC) (union sigval); + + IntervalTimer(); + ~IntervalTimer(); + bool set(int ms, TIMER_FUNC cb); + void kill(); + bool create(TIMER_FUNC ); + +private: + timer_t mTimerId; + TIMER_FUNC mCb; +}; diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp new file mode 100644 index 0000000..4034a03 --- /dev/null +++ b/nci/jni/Mutex.cpp @@ -0,0 +1,127 @@ +/***************************************************************************** +** +** Name: Mutex.cpp +** +** Description: Encapsulate a mutex for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "Mutex.h" +#include "NfcJniUtil.h" +#include + +/******************************************************************************* +** +** Function: Mutex +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +Mutex::Mutex () +{ + memset (&mMutex, 0, sizeof(mMutex)); + int res = pthread_mutex_init (&mMutex, NULL); + if (res != 0) + { + ALOGE ("Mutex::Mutex: fail init; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: ~Mutex +** +** Description: Cleanup all resources. +** +** Returns: None. +** +*******************************************************************************/ +Mutex::~Mutex () +{ + int res = pthread_mutex_destroy (&mMutex); + if (res != 0) + { + ALOGE ("Mutex::~Mutex: fail destroy; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: lock +** +** Description: Block the thread and try lock the mutex. +** +** Returns: None. +** +*******************************************************************************/ +void Mutex::lock () +{ + int res = pthread_mutex_lock (&mMutex); + if (res != 0) + { + ALOGE ("Mutex::lock: fail lock; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: unlock +** +** Description: Unlock a mutex to unblock a thread. +** +** Returns: None. +** +*******************************************************************************/ +void Mutex::unlock () +{ + int res = pthread_mutex_unlock (&mMutex); + if (res != 0) + { + ALOGE ("Mutex::lock: fail unlock; error=0x%X", res); + } +} + + +/******************************************************************************* +** +** Function: tryLock +** +** Description: Try to lock the mutex. +** +** Returns: True if the mutex is locked. +** +*******************************************************************************/ +bool Mutex::tryLock () +{ + int res = pthread_mutex_trylock (&mMutex); + if ((res != 0) && (res != EBUSY)) + { + ALOGE ("Mutex::lock: fail try-lock; error=0x%X", res); + } + return res == 0; +} + + +/******************************************************************************* +** +** Function: nativeHandle +** +** Description: Get the handle of the mutex. +** +** Returns: Handle of the mutex. +** +*******************************************************************************/ +pthread_mutex_t* Mutex::nativeHandle () +{ + return &mMutex; +} + + diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h new file mode 100644 index 0000000..c858e8e --- /dev/null +++ b/nci/jni/Mutex.h @@ -0,0 +1,93 @@ +/***************************************************************************** +** +** Name: Mutex.h +** +** Description: Encapsulate a mutex for thread synchronization. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include + + +class Mutex +{ +public: + /******************************************************************************* + ** + ** Function: Mutex + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + Mutex (); + + + /******************************************************************************* + ** + ** Function: ~Mutex + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~Mutex (); + + + /******************************************************************************* + ** + ** Function: lock + ** + ** Description: Block the thread and try lock the mutex. + ** + ** Returns: None. + ** + *******************************************************************************/ + void lock (); + + + /******************************************************************************* + ** + ** Function: unlock + ** + ** Description: Unlock a mutex to unblock a thread. + ** + ** Returns: None. + ** + *******************************************************************************/ + void unlock (); + + + /******************************************************************************* + ** + ** Function: tryLock + ** + ** Description: Try to lock the mutex. + ** + ** Returns: True if the mutex is locked. + ** + *******************************************************************************/ + bool tryLock (); + + + /******************************************************************************* + ** + ** Function: nativeHandle + ** + ** Description: Get the handle of the mutex. + ** + ** Returns: Handle of the mutex. + ** + *******************************************************************************/ + pthread_mutex_t* nativeHandle (); + +private: + pthread_mutex_t mMutex; +}; + diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp new file mode 100644 index 0000000..88361a6 --- /dev/null +++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "NfcJniUtil.h" +extern "C" +{ + #include "nfa_api.h" + #include "nfa_p2p_api.h" +} + + +namespace android +{ + + +extern char* gNativeLlcpConnectionlessSocketClassName; + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ +static sem_t sConnlessRecvSem; +static jboolean sConnlessRecvWaitingForData = JNI_FALSE; +static uint8_t* sConnlessRecvBuf = NULL; +static uint32_t sConnlessRecvLen = 0; +static uint32_t sConnlessRecvRemoteSap = 0; + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_doSendTo +** +** Description: Send data to peer. +** e: JVM environment. +** o: Java object. +** nsap: service access point. +** data: buffer for data. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + jint handle = 0; + uint8_t* buf = NULL; + uint32_t len = 0; + jclass c = NULL; + jfieldID f = NULL; + + ALOGD ("%s: nsap = %d", __FUNCTION__, nsap); + + c = e->GetObjectClass (o); + f = e->GetFieldID (c, "mHandle", "I"); + handle = e->GetIntField (o, f); + + buf = (uint8_t*) e->GetByteArrayElements (data, NULL); + len = (uint32_t) e->GetArrayLength (data); + + ALOGD ("NFA_P2pSendUI: len = %d", len); + status = NFA_P2pSendUI ((tNFA_HANDLE) handle, nsap, len, buf); + + ALOGD ("%s: NFA_P2pSendUI done, status = %d", __FUNCTION__, status); + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_P2pSendUI failed, status = %d", __FUNCTION__, status); + return JNI_FALSE; + } + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_receiveData +** +** Description: Receive data from the stack. +** data: buffer contains data. +** len: length of data. +** remoteSap: remote service access point. +** +** Returns: None +** +*******************************************************************************/ +void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remoteSap) +{ + ALOGD ("%s: waiting for data = %d, len = %d", __FUNCTION__, sConnlessRecvWaitingForData, len); + + // Sanity... + if (sConnlessRecvLen < len) + { + len = sConnlessRecvLen; + } + + if (sConnlessRecvWaitingForData) + { + sConnlessRecvWaitingForData = JNI_FALSE; + sConnlessRecvLen = len; + memcpy (sConnlessRecvBuf, data, len); + sConnlessRecvRemoteSap = remoteSap; + + sem_post (&sConnlessRecvSem); + } +} + + +/******************************************************************************* +** +** Function: connectionlessCleanup +** +** Description: Free resources. +** +** Returns: None +** +*******************************************************************************/ +static jobject connectionlessCleanup () +{ + sConnlessRecvWaitingForData = JNI_FALSE; + sConnlessRecvLen = 0; + if (sConnlessRecvBuf != NULL) + { + free (sConnlessRecvBuf); + sConnlessRecvBuf = NULL; + } + return NULL; +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_abortWait +** +** Description: Abort current operation and unblock threads. +** +** Returns: None +** +*******************************************************************************/ +void nativeLlcpConnectionlessSocket_abortWait () +{ + sem_post (&sConnlessRecvSem); +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_doReceiveFrom +** +** Description: Receive data from a peer. +** e: JVM environment. +** o: Java object. +** linkMiu: max info unit +** +** Returns: LlcpPacket Java object. +** +*******************************************************************************/ +static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv *e, jobject o, jint linkMiu) +{ + jbyteArray receivedData = NULL; + jobject llcpPacket = NULL; + jclass clsLlcpPacket = NULL; + jfieldID f = NULL; + + ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu); + + if (sConnlessRecvWaitingForData != JNI_FALSE) + { + ALOGD ("%s: Already waiting for incoming data", __FUNCTION__); + return NULL; + } + + sConnlessRecvBuf = (uint8_t*) malloc (linkMiu); + if (sConnlessRecvBuf == NULL) + { + ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu); + return NULL; + } + sConnlessRecvLen = linkMiu; + + // Create the write semaphore + if (sem_init (&sConnlessRecvSem, 0, 0) == -1) + { + ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return connectionlessCleanup (); + } + + sConnlessRecvWaitingForData = JNI_TRUE; + + // Wait for sConnlessRecvSem completion status + if (sem_wait (&sConnlessRecvSem)) + { + ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + // Create new LlcpPacket object + if (nfc_jni_cache_object (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1) + { + ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__); + return connectionlessCleanup (); + } + + // Get NativeConnectionless class object + clsLlcpPacket = e->GetObjectClass (llcpPacket); + if (e->ExceptionCheck ()) + { + e->ExceptionClear(); + ALOGE ("%s: Get Object class error", __FUNCTION__); + return connectionlessCleanup (); + } + + // Set Llcp Packet remote SAP + f = e->GetFieldID (clsLlcpPacket, "mRemoteSap", "I"); + e->SetIntField (llcpPacket, f, (jbyte) sConnlessRecvRemoteSap); + + // Set Llcp Packet Buffer + ALOGD ("%s: Received Llcp packet buffer size = %d\n", __FUNCTION__, sConnlessRecvLen); + f = e->GetFieldID (clsLlcpPacket, "mDataBuffer", "[B"); + receivedData = e->NewByteArray (sConnlessRecvLen); + e->SetByteArrayRegion (receivedData, 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf); + e->SetObjectField (llcpPacket, f, receivedData); + +TheEnd: + connectionlessCleanup (); + if (sem_destroy (&sConnlessRecvSem)) + { + ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + return llcpPacket; +} + + +/******************************************************************************* +** +** Function: nativeLlcpConnectionlessSocket_doClose +** +** Description: Close socket. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + jint handle = 0; + jclass c = NULL; + jfieldID f = NULL; + + ALOGD ("%s", __FUNCTION__); + + c = e->GetObjectClass (o); + f = e->GetFieldID (c, "mHandle", "I"); + handle = e->GetIntField (o, f); + + status = NFA_P2pDisconnect ((tNFA_HANDLE) handle, FALSE); + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status); + return JNI_FALSE; + } + return JNI_TRUE; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo}, + {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom}, + {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeLlcpConnectionlessSocket +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e) +{ + return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods)); +} + + +} // android namespace diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp new file mode 100644 index 0000000..8b05b8e --- /dev/null +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NfcJniUtil.h" +#include "NfcAdaptation.h" +#include "PeerToPeer.h" +extern "C" +{ + #include "nfa_api.h" + #include "nfa_p2p_api.h" +} +extern tBRCM_JNI_HANDLE gNextJniHandle; + + +namespace android +{ + + +extern char* gNativeLlcpServiceSocketClassName; +extern char* gNativeLlcpSocketClassName; + + +/******************************************************************************* +** +** Function: nativeLlcpServiceSocket_doAccept +** +** Description: Accept a connection request from a peer. +** e: JVM environment. +** o: Java object. +** miu: Maximum information unit. +** rw: Receive window. +** linearBufferLength: Not used. +** +** Returns: LlcpSocket Java object. +** +*******************************************************************************/ +static jobject nativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength) +{ + jobject clientSocket = NULL; + jclass clsNativeLlcpSocket = NULL; + jfieldID f = 0; + tBRCM_JNI_HANDLE serverHandle; //handle of the local server + bool stat = false; + tBRCM_JNI_HANDLE connHandle = gNextJniHandle++; + + ALOGD ("%s: enter", __FUNCTION__); + + serverHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e, o); + + stat = PeerToPeer::getInstance().accept (serverHandle, connHandle, miu, rw); + + if (! stat) + { + ALOGE ("%s: fail accept", __FUNCTION__); + goto TheEnd; + } + + /* Create new LlcpSocket object */ + if (nfc_jni_cache_object(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1) + { + ALOGE ("%s: fail create NativeLlcpSocket", __FUNCTION__); + goto TheEnd; + } + + /* Get NativeConnectionOriented class object */ + clsNativeLlcpSocket = e->GetObjectClass (clientSocket); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: get class object error", __FUNCTION__); + goto TheEnd; + } + + /* Set socket handle */ + f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField (clientSocket, f, (jint) connHandle); + + /* Set socket MIU */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField (clientSocket, f, (jint)miu); + + /* Set socket RW */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField (clientSocket, f, (jint)rw); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return clientSocket; +} + + +/******************************************************************************* +** +** Function: nativeLlcpServiceSocket_doClose +** +** Description: Close a server socket. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + tBRCM_JNI_HANDLE jniServerHandle = 0; + bool stat = false; + + jniServerHandle = nfc_jni_get_nfc_socket_handle (e, o); + + stat = PeerToPeer::getInstance().deregisterServer (jniServerHandle); + + ALOGD ("%s: exit", __FUNCTION__); + return JNI_TRUE; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void*) nativeLlcpServiceSocket_doAccept}, + {"doClose", "()Z", (void*) nativeLlcpServiceSocket_doClose}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeLlcpServiceSocket +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv* e) +{ + return jniRegisterNativeMethods (e, gNativeLlcpServiceSocketClassName, + gMethods, NELEM(gMethods)); +} + + +} //namespace android + diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp new file mode 100644 index 0000000..cad6268 --- /dev/null +++ b/nci/jni/NativeLlcpSocket.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NfcJniUtil.h" +#include "PeerToPeer.h" + + +namespace android +{ + + +extern char* gNativeLlcpSocketClassName; + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doConnect +** +** Description: Establish a connection to the peer. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doConnect (JNIEnv* e, jobject o, jint nSap) +{ + bool stat = false; + jboolean retVal = JNI_FALSE; + + ALOGD ("%s: enter; sap=%d", __FUNCTION__, nSap); + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, nSap); + + if (stat) + retVal = JNI_TRUE; + + ALOGD ("%s: exit", __FUNCTION__); + return retVal; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doConnectBy +** +** Description: Establish a connection to the peer. +** e: JVM environment. +** o: Java object. +** sn: Service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + jboolean retVal = JNI_FALSE; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* + + stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, serviceName); + + e->ReleaseStringUTFChars (sn, serviceName); //free the string + + if (stat) + retVal = JNI_TRUE; + + ALOGD ("%s: exit", __FUNCTION__); + return retVal; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doClose +** +** Description: Close socket. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + jboolean retVal = JNI_FALSE; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().disconnectConnOriented (jniHandle); + + retVal = JNI_TRUE; + ALOGD ("%s: exit", __FUNCTION__); + return retVal; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doSend +** +** Description: Send data to peer. +** e: JVM environment. +** o: Java object. +** data: Buffer of data. +** +** Returns: True if sent ok. +** +*******************************************************************************/ +static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data) +{ + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); + uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (data, NULL); + uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (data); + bool stat = false; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().send (jniHandle, dataBuffer, dataBufferLen); + + e->ReleaseByteArrayElements (data, (jbyte*) dataBuffer, JNI_ABORT); + + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__); + return stat ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doReceive +** +** Description: Receive data from peer. +** e: JVM environment. +** o: Java object. +** origBuffer: Buffer to put received data. +** +** Returns: Number of bytes received. +** +*******************************************************************************/ +static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuffer) +{ + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); + uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (origBuffer, NULL); + uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (origBuffer); + uint16_t actualLen = 0; + bool stat = false; + jint retval = 0; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + stat = PeerToPeer::getInstance().receive (jniHandle, dataBuffer, dataBufferLen, actualLen); + + if (stat && (actualLen>0)) + { + retval = actualLen; + } + else + retval = -1; + + e->ReleaseByteArrayElements (origBuffer, (jbyte*) dataBuffer, 0); + ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doGetRemoteSocketMIU +** +** Description: Get peer's maximum information unit. +** e: JVM environment. +** o: Java object. +** +** Returns: Peer's maximum information unit. +** +*******************************************************************************/ +static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + jint miu = 0; + + miu = PeerToPeer::getInstance().getRemoteMaxInfoUnit (jniHandle); + + ALOGD ("%s: exit", __FUNCTION__); + return miu; +} + + +/******************************************************************************* +** +** Function: nativeLlcpSocket_doGetRemoteSocketRW +** +** Description: Get peer's receive window size. +** e: JVM environment. +** o: Java object. +** +** Returns: Peer's receive window size. +** +*******************************************************************************/ +static jint nativeLlcpSocket_doGetRemoteSocketRW (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + jint rw = 0; + + tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + + rw = PeerToPeer::getInstance().getRemoteRecvWindow (jniHandle); + + ALOGD ("%s: exit", __FUNCTION__); + return rw; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)Z", (void * ) nativeLlcpSocket_doConnect}, + {"doConnectBy", "(Ljava/lang/String;)Z", (void*) nativeLlcpSocket_doConnectBy}, + {"doClose", "()Z", (void *) nativeLlcpSocket_doClose}, + {"doSend", "([B)Z", (void *) nativeLlcpSocket_doSend}, + {"doReceive", "([B)I", (void *) nativeLlcpSocket_doReceive}, + {"doGetRemoteSocketMiu", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketMIU}, + {"doGetRemoteSocketRw", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketRW}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeLlcpSocket +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeLlcpSocket (JNIEnv* e) +{ + return jniRegisterNativeMethods (e, gNativeLlcpSocketClassName, gMethods, NELEM(gMethods)); +} + + +} //namespace android + diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp new file mode 100755 index 0000000..0648852 --- /dev/null +++ b/nci/jni/NativeNfcManager.cpp @@ -0,0 +1,1686 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "NfcJniUtil.h" +#include "NfcAdaptation.h" +#include "SyncEvent.h" +#include "PeerToPeer.h" +#include "SecureElement.h" +#include "NfcTag.h" +#include "config.h" +#include "PowerSwitch.h" + +extern "C" +{ + #include "nfa_api.h" + #include "nfa_p2p_api.h" + #include "nfa_dta_api.h" + #include "rw_api.h" + #include "nfa_ee_api.h" + #include "nfa_brcm_api.h" + #include "nfa_cho_api.h" +} + +extern UINT8 *p_nfa_dm_lptd_cfg; +extern UINT8 *p_nfa_dm_start_up_cfg; +extern const UINT8 nfca_version_string []; +extern "C" void nfa_app_post_nci_reset (); +namespace android +{ + extern bool gIsTagDeactivating; + extern bool gIsSelectingRfInterface; + extern void nativeNfcTag_doTranseiveStatus (uint8_t * buf, uint32_t buflen); + extern void nativeNfcTag_doConnectStatus (jboolean is_connect_ok); + extern void nativeNfcTag_doDeactivateStatus (int status); + extern void nativeNfcTag_doWriteStatus (jboolean is_write_ok); + extern void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t max_size, uint32_t current_size, uint8_t flags); + extern void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status); + extern void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status); + extern void nativeNfcTag_formatStatus (bool is_ok); + extern void nativeNfcTag_resetPresenceCheck (); + extern void nativeNfcTag_doReadCompleted (tNFA_STATUS status); + extern void nativeNfcTag_abortWaits (); + extern void nativeLlcpConnectionlessSocket_abortWait (); + extern void nativeNfcTag_registerNdefTypeHandler (); + extern void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remote_sap); +} + + +/***************************************************************************** +** +** public variables and functions +** +*****************************************************************************/ +tBRCM_JNI_HANDLE gNextJniHandle = 1; +long gJniVersion = 411; + +namespace android +{ + int gGeneralTransceiveTimeout = 1000; + jmethodID gCachedNfcManagerNotifyNdefMessageListeners; + jmethodID gCachedNfcManagerNotifyTransactionListeners; + jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; + jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; + jmethodID gCachedNfcManagerNotifySeFieldActivated; + jmethodID gCachedNfcManagerNotifySeFieldDeactivated; + const char* gNativeP2pDeviceClassName = "com/android/nfc/dhimpl/NativeP2pDevice"; + const char* gNativeLlcpServiceSocketClassName = "com/android/nfc/dhimpl/NativeLlcpServiceSocket"; + const char* gNativeLlcpConnectionlessSocketClassName = "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket"; + const char* gNativeLlcpSocketClassName = "com/android/nfc/dhimpl/NativeLlcpSocket"; + const char* gNativeNfcTagClassName = "com/android/nfc/dhimpl/NativeNfcTag"; + const char* gNativeNfcManagerClassName = "com/android/nfc/dhimpl/NativeNfcManager"; + const char* gNativeNfcSecureElementClassName = "com/android/nfc/dhimpl/NativeNfcSecureElement"; + void doStartupConfig (); +} + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ +namespace android +{ +static jint sLastError = ERROR_BUFFER_TOO_SMALL; +static jmethodID sCachedNfcManagerNotifySeApduReceived; +static jmethodID sCachedNfcManagerNotifySeMifareAccess; +static jmethodID sCachedNfcManagerNotifySeEmvCardRemoval; +static jmethodID sCachedNfcManagerNotifyTargetDeselected; +static SyncEvent sNfaEnableEvent; //event for NFA_Enable() +static SyncEvent sNfaDisableEvent; //event for NFA_Disable() +static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling() +static SyncEvent sNfaSetConfigEvent; // event for Set_Config.... +static bool sIsNfaEnabled = false; +static bool sDiscoveryEnabled = false; //is polling for tag? +static bool sIsDisabling = false; +#define NFA_DM_PWR_STATE_UNKNOWN (-1) // power off sleep state is unkown until is is reported back from NFA... +static int sConnlessSap = 0; +static int sConnlessLinkMiu = 0; +static bool sAbortConnlessWait = false; +static bool sIsSecElemSelected = false; //has NFC service selected a sec elem +static UINT8 * sOriginalLptdCfg = NULL; +#define LPTD_PARAM_LEN (30) +static UINT8 sNewLptdCfg[LPTD_PARAM_LEN]; +static UINT32 sConfigUpdated = 0; +#define CONFIG_UPDATE_LPTD (1 << 0) +#define CONFIG_UPDATE_TECH_MASK (1 << 1) +#define DEFAULT_TECH_MASK (NFA_TECHNOLOGY_MASK_A \ + | NFA_TECHNOLOGY_MASK_B \ + | NFA_TECHNOLOGY_MASK_F \ + | NFA_TECHNOLOGY_MASK_ISO15693 \ + | NFA_TECHNOLOGY_MASK_B_PRIME \ + | NFA_TECHNOLOGY_MASK_A_ACTIVE \ + | NFA_TECHNOLOGY_MASK_F_ACTIVE) + + +static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); +static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); +static bool isPeerToPeer (tNFA_ACTIVATED& activated); +static void startRfDiscovery (bool isStart); +static void nfaBrcmInitCallback (UINT32 brcm_hw_id); + +///////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: getNative +** +** Description: Get native data +** +** Returns: Native data structure. +** +*******************************************************************************/ +nfc_jni_native_data *getNative (JNIEnv* e, jobject o) +{ + static struct nfc_jni_native_data *sCachedNat = NULL; + if (e) + { + sCachedNat = nfc_jni_get_nat(e, o); + } + return sCachedNat; +} + + +/******************************************************************************* +** +** Function: handleRfDiscoveryEvent +** +** Description: Handle RF-discovery events from the stack. +** discoveredDevice: Discovered device. +** +** Returns: None +** +*******************************************************************************/ +static void handleRfDiscoveryEvent (tNFC_RESULT_DEVT* discoveredDevice) +{ + if (discoveredDevice->more) + { + //there is more discovery notification coming + return; + } + + bool isP2p = NfcTag::getInstance ().isP2pDiscovered (); + if (isP2p) + { + //select the peer that supports P2P + NfcTag::getInstance ().selectP2p(); + } + else + { + //select the first of multiple tags that is discovered + NfcTag::getInstance ().selectFirstTag(); + } +} + + +/******************************************************************************* +** +** Function: nfaConnectionCallback +** +** Description: Receive connection-related events from stack. +** connEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventData) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + ALOGD("%s: event= %u", __FUNCTION__, connEvent); + + if (gIsTagDeactivating && connEvent != NFA_DEACTIVATED_EVT && connEvent != NFA_PRESENCE_CHECK_EVT && connEvent != NFA_DATA_EVT) + { + // special case to switching frame interface for ISO_DEP tags + gIsTagDeactivating = false; + ALOGD("%s: deactivating, should get NFA_DEACTIVATED_EVT", __FUNCTION__); + nativeNfcTag_doDeactivateStatus(1); + } + + switch (connEvent) + { + case NFA_POLL_ENABLED_EVT: // whether polling successfully started + { + ALOGD("%s: NFA_POLL_ENABLED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_POLL_DISABLED_EVT: // Listening/Polling stopped + { + ALOGD("%s: NFA_POLL_DISABLED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started + { + ALOGD("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event + { + ALOGD("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __FUNCTION__, eventData->status); + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + break; + + case NFA_DISC_RESULT_EVT: // NFC link/protocol discovery notificaiton + status = eventData->disc_result.status; + ALOGD("%s: NFA_DISC_RESULT_EVT: status = %d", __FUNCTION__, status); + if (status != NFA_STATUS_OK) + { + ALOGE("%s: NFA_DISC_RESULT_EVT error: status = %d", __FUNCTION__, status); + } + else + { + NfcTag::getInstance().connectionEventHandler(connEvent, eventData); + handleRfDiscoveryEvent(&eventData->disc_result.discovery_ntf); + } + break; + + case NFA_SELECT_RESULT_EVT: // NFC link/protocol discovery select response + ALOGD("%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = %d", __FUNCTION__, eventData->status, gIsSelectingRfInterface); + + if (eventData->status != NFA_STATUS_OK) + { + if (gIsSelectingRfInterface) + { + nativeNfcTag_doConnectStatus(false); + } + + ALOGE("%s: NFA_SELECT_RESULT_EVT error: status = %d", __FUNCTION__, eventData->status); + NFA_Deactivate (FALSE); + } + break; + + case NFA_DEACTIVATE_FAIL_EVT: + ALOGD("%s: NFA_DEACTIVATE_FAIL_EVT: status = %d", __FUNCTION__, eventData->status); + break; + + case NFA_ACTIVATED_EVT: // NFC link/protocol activated + ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d", __FUNCTION__, gIsSelectingRfInterface); + if (gIsSelectingRfInterface) + { + nativeNfcTag_doConnectStatus(true); + break; + } + + nativeNfcTag_resetPresenceCheck(); + if (isPeerToPeer(eventData->activated)) + { + ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); + break; + } + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + break; + + case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated + ALOGD("%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __FUNCTION__, eventData->deactivated.type,gIsTagDeactivating); + if (gIsTagDeactivating || gIsSelectingRfInterface) + { + if (gIsTagDeactivating) + nativeNfcTag_doDeactivateStatus(0); + break; + } + nativeNfcTag_resetPresenceCheck(); + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + break; + + case NFA_TLV_DETECT_EVT: // TLV Detection complete + status = eventData->tlv_detect.status; + ALOGD("%s: NFA_TLV_DETECT_EVT: status = %d, protocol = %d, num_tlvs = %d, num_bytes = %d", + __FUNCTION__, status, eventData->tlv_detect.protocol, + eventData->tlv_detect.num_tlvs, eventData->tlv_detect.num_bytes); + if (status != NFA_STATUS_OK) + { + ALOGE("%s: NFA_TLV_DETECT_EVT error: status = %d", __FUNCTION__, status); + } + break; + + case NFA_NDEF_DETECT_EVT: // NDEF Detection complete; + //if status is failure, it means the tag does not contain any or valid NDEF data; + //pass the failure status to the NFC Service; + status = eventData->ndef_detect.status; + ALOGD("%s: NFA_NDEF_DETECT_EVT: status = 0x%X, protocol = %u, " + "max_size = %lu, cur_size = %lu, flags = 0x%X", __FUNCTION__, + status, + eventData->ndef_detect.protocol, eventData->ndef_detect.max_size, + eventData->ndef_detect.cur_size, eventData->ndef_detect.flags); + nativeNfcTag_doCheckNdefResult(status, + eventData->ndef_detect.max_size, eventData->ndef_detect.cur_size, + eventData->ndef_detect.flags); + break; + + case NFA_DATA_EVT: // Data message received (for non-NDEF reads) + ALOGD("%s: NFA_DATA_EVT: len = %d", __FUNCTION__, eventData->data.len); + nativeNfcTag_doTranseiveStatus(eventData->data.p_data,eventData->data.len); + break; + + case NFA_SELECT_CPLT_EVT: // Select completed + status = eventData->status; + ALOGD("%s: NFA_SELECT_CPLT_EVT: status = %d", __FUNCTION__, status); + if (status != NFA_STATUS_OK) + { + ALOGE("%s: NFA_SELECT_CPLT_EVT error: status = %d", __FUNCTION__, status); + } + break; + + case NFA_READ_CPLT_EVT: // NDEF-read or tag-specific-read completed + ALOGD("%s: NFA_READ_CPLT_EVT: status = 0x%X", __FUNCTION__, eventData->status); + nativeNfcTag_doReadCompleted (eventData->status); + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + break; + + case NFA_WRITE_CPLT_EVT: // Write completed + ALOGD("%s: NFA_WRITE_CPLT_EVT: status = %d", __FUNCTION__, eventData->status); + nativeNfcTag_doWriteStatus (eventData->status == NFA_STATUS_OK); + break; + + case NFA_SET_TAG_RO_EVT: // Tag set as Read only + ALOGD("%s: NFA_SET_TAG_RO_EVT: status = %d", __FUNCTION__, eventData->status); + nativeNfcTag_doMakeReadonlyResult(eventData->status); + break; + + case NFA_CE_NDEF_WRITE_START_EVT: // NDEF write started + ALOGD("%s: NFA_CE_NDEF_WRITE_START_EVT: status: %d", __FUNCTION__, eventData->status); + + if (eventData->status != NFA_STATUS_OK) + ALOGE("%s: NFA_CE_NDEF_WRITE_START_EVT error: status = %d", __FUNCTION__, eventData->status); + break; + + case NFA_CE_NDEF_WRITE_CPLT_EVT: // NDEF write completed + ALOGD("%s: FA_CE_NDEF_WRITE_CPLT_EVT: len = %lu", __FUNCTION__, eventData->ndef_write_cplt.len); + break; + + case NFA_LLCP_ACTIVATED_EVT: // LLCP link is activated + ALOGD("%s: NFA_LLCP_ACTIVATED_EVT: is_initiator: %d remote_wks: %d, remote_lsc: %d, remote_link_miu: %d, local_link_miu: %d", + __FUNCTION__, + eventData->llcp_activated.is_initiator, + eventData->llcp_activated.remote_wks, + eventData->llcp_activated.remote_lsc, + eventData->llcp_activated.remote_link_miu, + eventData->llcp_activated.local_link_miu); + + PeerToPeer::getInstance().llcpActivatedHandler (getNative(0, 0), eventData->llcp_activated); + break; + + case NFA_LLCP_DEACTIVATED_EVT: // LLCP link is deactivated + ALOGD("%s: NFA_LLCP_DEACTIVATED_EVT", __FUNCTION__); + PeerToPeer::getInstance().llcpDeactivatedHandler (getNative(0, 0), eventData->llcp_deactivated); + break; + + case NFA_PRESENCE_CHECK_EVT: + ALOGD("%s: NFA_PRESENCE_CHECK_EVT", __FUNCTION__); + nativeNfcTag_doPresenceCheckResult (eventData->status); + break; + + case NFA_FORMAT_CPLT_EVT: + ALOGD("%s: NFA_FORMAT_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status); + nativeNfcTag_formatStatus (eventData->status == NFA_STATUS_OK); + break; + + case NFA_I93_CMD_CPLT_EVT: + ALOGD("%s: NFA_I93_CMD_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status); + break; + + case NFA_CE_UICC_LISTEN_CONFIGURED_EVT : + ALOGD("%s: NFA_CE_UICC_LISTEN_CONFIGURED_EVT : status=0x%X", __FUNCTION__, eventData->status); + SecureElement::getInstance().connectionEventHandler (connEvent, eventData); + break; + + case NFA_SET_P2P_LISTEN_TECH_EVT: + ALOGD("%s: NFA_SET_P2P_LISTEN_TECH_EVT", __FUNCTION__); + PeerToPeer::getInstance().connectionEventHandler (connEvent, eventData); + break; + + default: + ALOGE("%s: unknown event ????", __FUNCTION__); + break; + } +} + + +/******************************************************************************* +** +** Function: nfcManager_initNativeStruc +** +** Description: Initialize variables. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) +{ + nfc_jni_native_data* nat = NULL; + jclass cls = NULL; + jobject obj = NULL; + jfieldID f = 0; + + ALOGD ("%s: enter", __FUNCTION__); + + nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); + if (nat == NULL) + { + ALOGE ("%s: fail allocate native data", __FUNCTION__); + return JNI_FALSE; + } + + memset (nat, 0, sizeof(*nat)); + e->GetJavaVM (&(nat->vm)); + nat->env_version = e->GetVersion (); + nat->manager = e->NewGlobalRef (o); + + cls = e->GetObjectClass (o); + f = e->GetFieldID (cls, "mNative", "I"); + e->SetIntField (o, f, (jint)nat); + + /* Initialize native cached references */ + gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID (cls, + "notifyNdefMessageListeners",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V" : "(Lcom/android/nfc/NativeNfcTag;)V"); + gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID (cls, + "notifyTransactionListeners", "([B)V"); + gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID (cls, + "notifyLlcpLinkActivation",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V" : "(Lcom/android/nfc/NativeP2pDevice;)V"); + gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID (cls, + "notifyLlcpLinkDeactivated",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V" : "(Lcom/android/nfc/NativeP2pDevice;)V"); + sCachedNfcManagerNotifyTargetDeselected = e->GetMethodID (cls, + "notifyTargetDeselected","()V"); + gCachedNfcManagerNotifySeFieldActivated = e->GetMethodID (cls, + "notifySeFieldActivated", "()V"); + gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID (cls, + "notifySeFieldDeactivated", "()V"); + + if (gJniVersion > 235) + { + sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls, + "notifySeApduReceived", "([B)V"); + + sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls, + "notifySeMifareAccess", "([B)V"); + + sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls, + "notifySeEmvCardRemoval", "()V"); + } + else + { + sCachedNfcManagerNotifySeApduReceived = NULL; + sCachedNfcManagerNotifySeMifareAccess = NULL; + sCachedNfcManagerNotifySeEmvCardRemoval = NULL; + } + + if (nfc_jni_cache_object(e,gNativeNfcTagClassName, &(nat->cached_NfcTag)) == -1) + { + ALOGE ("%s: fail cache NativeNfcTag", __FUNCTION__); + return JNI_FALSE; + } + + if (nfc_jni_cache_object(e,gNativeP2pDeviceClassName, &(nat->cached_P2pDevice)) == -1) + { + ALOGE ("%s: fail cache NativeP2pDevice", __FUNCTION__); + return JNI_FALSE; + } + + unsigned long num = 0; + + if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) + nat->tech_mask = num; + else + nat->tech_mask = DEFAULT_TECH_MASK; + + ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); + + // Always restore LPTD Configuration to the stack default. + if (sOriginalLptdCfg != NULL) + p_nfa_dm_lptd_cfg = sOriginalLptdCfg; + else + sOriginalLptdCfg = p_nfa_dm_lptd_cfg; + + // Override LPTD from the config file if it is found. + if (GetStrValue(NAME_LPTD_CFG, (char*)&sNewLptdCfg[0], sizeof(sNewLptdCfg))) + { + // Set stack pointer to use value. + p_nfa_dm_lptd_cfg = &sNewLptdCfg[0]; + } + + PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); + + ALOGD ("%s: exit", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfaDeviceManagementCallback +** +** Description: Receive device management events from stack. +** dmEvent: Device-management event ID. +** eventData: Data associated with event ID. +** +** Returns: None +** +*******************************************************************************/ +void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) +{ + ALOGD ("%s: enter; event=0x%X", __FUNCTION__, dmEvent); + + switch (dmEvent) + { + case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */ + { + SyncEventGuard guard (sNfaEnableEvent); + ALOGD ("%s: NFA_DM_ENABLE_EVT; status=0x%X", + __FUNCTION__, eventData->status); + sIsNfaEnabled = eventData->status == NFA_STATUS_OK; + sIsDisabling = false; + sNfaEnableEvent.notifyOne (); + } + break; + + case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */ + { + SyncEventGuard guard (sNfaDisableEvent); + ALOGD ("%s: NFA_DM_DISABLE_EVT", __FUNCTION__); + sIsNfaEnabled = false; + sIsDisabling = false; + sNfaDisableEvent.notifyOne (); + } + break; + + case NFA_DM_SET_CONFIG_EVT: //result of NFA_SetConfig + ALOGD ("%s: NFA_DM_SET_CONFIG_EVT", __FUNCTION__); + { + SyncEventGuard guard (sNfaSetConfigEvent); + sNfaSetConfigEvent.notifyOne(); + } + break; + + case NFA_DM_GET_CONFIG_EVT: /* Result of NFA_GetConfig */ + ALOGD ("%s: NFA_DM_GET_CONFIG_EVT", __FUNCTION__); + break; + + case NFA_DM_RF_FIELD_EVT: + ALOGD ("%s: NFA_DM_RF_FIELD_EVT; status=0x%X; field status=%u", __FUNCTION__, + eventData->rf_field.status, eventData->rf_field.rf_field_status); + + if (eventData->rf_field.status == NFA_STATUS_OK) + SecureElement::getInstance().notifyRfFieldEvent (eventData->rf_field.rf_field_status == NFA_DM_RF_FIELD_ON); + break; + + case NFA_DM_NFCC_TRANSPORT_ERR_EVT: + case NFA_DM_NFCC_TIMEOUT_EVT: + { + if (dmEvent == NFA_DM_NFCC_TIMEOUT_EVT) + ALOGD ("%s: NFA_DM_NFCC_TIMEOUT_EVT; abort all outstanding operations", __FUNCTION__); + else + ALOGD ("%s: NFA_DM_NFCC_TRANSPORT_ERR_EVT; abort all outstanding operations", __FUNCTION__); + + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + sAbortConnlessWait = true; + nativeLlcpConnectionlessSocket_abortWait(); + { + ALOGD ("%s: aborting sNfaEnableDisablePollingEvent", __FUNCTION__); + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne(); + } + { + ALOGD ("%s: aborting sNfaEnableEvent", __FUNCTION__); + SyncEventGuard guard (sNfaEnableEvent); + sNfaEnableEvent.notifyOne(); + } + { + ALOGD ("%s: aborting sNfaDisableEvent", __FUNCTION__); + SyncEventGuard guard (sNfaDisableEvent); + sNfaDisableEvent.notifyOne(); + } + sDiscoveryEnabled = false; + PowerSwitch::getInstance ().abort (); + + if (!sIsDisabling && sIsNfaEnabled) + { + NFA_Disable(FALSE); + sIsDisabling = true; + } + else + { + sIsNfaEnabled = false; + sIsDisabling = false; + } + PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL); + ALOGD ("%s: aborted all waiting events", __FUNCTION__); + } + break; + + case NFA_DM_PWR_MODE_CHANGE_EVT: + PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData); + break; + + default: + ALOGD ("%s: unhandled event", __FUNCTION__); + break; + } +} + + +/******************************************************************************* +** +** Function: nfcManager_doInitialize +** +** Description: Turn on NFC. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter; NCI_VERSION=0x%02X", __FUNCTION__, NCI_VERSION); + tNFA_STATUS stat = NFA_STATUS_OK; + + if (sIsNfaEnabled) + { + ALOGD ("%s: already enabled", __FUNCTION__); + goto TheEnd; + } + + { + unsigned long num = 0; + + NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); + theInstance.Initialize(); //start GKI, NCI task, NFC task + + SyncEventGuard guard (sNfaEnableEvent); + + NFA_Init(); + NFA_BrcmInit (nfaBrcmInitCallback); + + stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); + if (stat == NFA_STATUS_OK) + { + if (GetNumValue (NAME_APPL_TRACE_LEVEL, &num, sizeof (num))) + { + CE_SetTraceLevel (num); + LLCP_SetTraceLevel (num); + NFC_SetTraceLevel (num); + NCI_SetTraceLevel (num); + RW_SetTraceLevel (num); + NFA_SetTraceLevel (num); + NFA_ChoSetTraceLevel (num); + NFA_P2pSetTraceLevel (num); + NFA_SnepSetTraceLevel (num); + } + sNfaEnableEvent.wait(); //wait for NFA command to finish + + //sIsNfaEnabled indicates whether stack started successfully + if (sIsNfaEnabled) + { + SecureElement::getInstance().initialize (getNative(e, o)); + nativeNfcTag_registerNdefTypeHandler (); + NfcTag::getInstance().initialize (getNative(e, o)); + PeerToPeer::getInstance().initialize (gJniVersion); + PeerToPeer::getInstance().handleNfcOnOff (true); + + ///////////////////////////////////////////////////////////////////////////////// + // Add extra configuration here (work-arounds, etc.) + + // if this value is not set or set and non-zero, enable multi-technology responses. + if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) + NFA_SetMultiTechRsp(TRUE); + + // if this value is not set or set and non-zero, enable sleep mode. + if (!GetNumValue(NAME_NFA_DM_ENABLE_SLEEP, &num, sizeof(num)) || (num != 0)) + NFA_EnableSnoozeMode(); + + // Do custom NFCA startup configuration. + doStartupConfig(); + goto TheEnd; + } + } + + ALOGE ("%s: fail nfa enable; error=0x%X", __FUNCTION__, stat); + + if (sIsNfaEnabled) + stat = NFA_Disable (FALSE /* ungraceful */); + + theInstance.Finalize(); + } + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nfcManager_enableDiscovery +** +** Description: Start polling and listening for devices. +** e: JVM environment. +** o: Java object. +** mode: Not used. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) +{ + tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK; + struct nfc_jni_native_data *nat = getNative(e, o); + + if (nat) + tech_mask = (tNFA_TECHNOLOGY_MASK)nat->tech_mask; + + ALOGD ("%s: enter; tech_mask = %02x", __FUNCTION__, tech_mask); + + if (sDiscoveryEnabled) + { + ALOGE ("%s: already polling", __FUNCTION__); + return; + } + + tNFA_STATUS stat = NFA_STATUS_OK; + + ALOGD ("%s: sIsSecElemSelected=%u", __FUNCTION__, sIsSecElemSelected); + + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); + + { + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + stat = NFA_EnablePolling (tech_mask); + if (stat == NFA_STATUS_OK) + { + ALOGD ("%s: Waiting for sNfaEnableDisablePollingEvent", __FUNCTION__); + sDiscoveryEnabled = true; + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_START_EVT + ALOGD ("%s: Finished Waiting for sNfaEnableDisablePollingEvent", __FUNCTION__); + } + else + { + ALOGE ("%s: fail enable discovery; error=0x%X", __FUNCTION__, stat); + } + } + + // Start P2P listening if tag polling was enabled or the mask was 0. + if (sDiscoveryEnabled || (tech_mask == 0)) + { + ALOGD ("%s: Enable p2pListening", __FUNCTION__); + PeerToPeer::getInstance().enableP2pListening (true); + + //if NFC service has deselected the sec elem, then apply default routes + if (!sIsSecElemSelected) + stat = SecureElement::getInstance().routeToDefault (); + } + + // Actually start discovery. + startRfDiscovery (true); + + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: nfcManager_disableDiscovery +** +** Description: Stop polling and listening for devices. +** e: JVM environment. +** o: Java object. +** +** Returns: None +** +*******************************************************************************/ +void nfcManager_disableDiscovery (JNIEnv* e, jobject o) +{ + tNFA_STATUS status = NFA_STATUS_OK; + ALOGD ("%s: enter;", __FUNCTION__); + + if (sDiscoveryEnabled == false) + { + ALOGD ("%s: already disabled", __FUNCTION__); + goto TheEnd; + } + + // Stop RF Discovery. + startRfDiscovery (false); + + if (sDiscoveryEnabled) + { + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + status = NFA_DisablePolling (); + if (status == NFA_STATUS_OK) + { + sDiscoveryEnabled = false; + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_STOP_EVT + } + else + ALOGE ("%s: Failed to disable polling; error=0x%X", __FUNCTION__, status); + } + + PeerToPeer::getInstance().enableP2pListening (false); + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); +} + +/******************************************************************************* +** +** Function nfc_jni_cache_object_local +** +** Description Allocates a java object and calls it's constructor +** +** Returns -1 on failure, 0 on success +** +*******************************************************************************/ +int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cachedObj) +{ + jclass cls = NULL; + jobject obj = NULL; + jmethodID ctor = 0; + + cls = e->FindClass (className); + if(cls == NULL) + { + ALOGE ("%s: find class error", __FUNCTION__); + return -1; + } + + ctor = e->GetMethodID (cls, "", "()V"); + obj = e->NewObject (cls, ctor); + if (obj == NULL) + { + ALOGE ("%s: create object error", __FUNCTION__); + return -1; + } + + *cachedObj = e->NewLocalRef (obj); + if (*cachedObj == NULL) + { + e->DeleteLocalRef (obj); + ALOGE ("%s: global ref error", __FUNCTION__); + return -1; + } + e->DeleteLocalRef (obj); + return 0; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCreateLlcpServiceSocket +** +** Description: Create a new LLCP server socket. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** sn: Service name +** miu: Maximum information unit. +** rw: Receive window size. +** linearBufferLength: Max buffer size. +** +** Returns: NativeLlcpServiceSocket Java object. +** +*******************************************************************************/ +static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) +{ + bool stat = false; + jobject serviceSocket = NULL; + jclass clsNativeLlcpServiceSocket = NULL; + jfieldID f = 0; + tBRCM_JNI_HANDLE jniHandle = gNextJniHandle++; + const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* + std::string serviceName2 (serviceName); + + e->ReleaseStringUTFChars (sn, serviceName); //free the string + ALOGD ("%s: enter: sap=%i; name=%s; miu=%i; rw=%i; buffLen=%i", __FUNCTION__, nSap, serviceName2.c_str(), miu, rw, linearBufferLength); + + /* Create new NativeLlcpServiceSocket object */ + if (nfc_jni_cache_object(e, gNativeLlcpServiceSocketClassName, &(serviceSocket)) == -1) + { + ALOGE ("%s: Llcp socket object creation error", __FUNCTION__); + return NULL; + } + + /* Get NativeLlcpServiceSocket class object */ + clsNativeLlcpServiceSocket = e->GetObjectClass (serviceSocket); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE("%s: Llcp Socket get object class error", __FUNCTION__); + return NULL; + } + + if (!PeerToPeer::getInstance().registerServer (jniHandle, serviceName2.c_str())) + { + ALOGE("%s: RegisterServer error", __FUNCTION__); + return NULL; + } + + /* Set socket handle to be the same as the NfaHandle*/ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mHandle", "I"); + e->SetIntField (serviceSocket, f, (jint) jniHandle); + ALOGD ("%s: socket Handle = 0x%X", __FUNCTION__, jniHandle); + + /* Set socket linear buffer length */ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); + e->SetIntField (serviceSocket, f,(jint)linearBufferLength); + ALOGD ("%s: buffer length = %d", __FUNCTION__, linearBufferLength); + + /* Set socket MIU */ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalMiu", "I"); + e->SetIntField (serviceSocket, f,(jint)miu); + ALOGD ("%s: MIU = %d", __FUNCTION__, miu); + + /* Set socket RW */ + f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalRw", "I"); + e->SetIntField (serviceSocket, f,(jint)rw); + ALOGD ("%s: RW = %d", __FUNCTION__, rw); + + sLastError = 0; + ALOGD ("%s: exit", __FUNCTION__); + return serviceSocket; +} + + +/******************************************************************************* +** +** Function: nfcManager_doGetLastError +** +** Description: Get the last error code. +** e: JVM environment. +** o: Java object. +** +** Returns: Last error code. +** +*******************************************************************************/ +static jint nfcManager_doGetLastError(JNIEnv* e, jobject o) +{ + ALOGD ("%s: last error=%i", __FUNCTION__, sLastError); + return sLastError; +} + + +/******************************************************************************* +** +** Function: nfcManager_doDeinitialize +** +** Description: Turn off NFC. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nfcManager_doDeinitialize (JNIEnv* e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + + sIsDisabling = true; + + SecureElement::getInstance().finalize (); + + if (sIsNfaEnabled) + { + SyncEventGuard guard (sNfaDisableEvent); + tNFA_STATUS stat = NFA_Disable (TRUE /* graceful */); + if (stat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for completion", __FUNCTION__); + sNfaDisableEvent.wait (); //wait for NFA command to finish + PeerToPeer::getInstance ().handleNfcOnOff (false); + } + else + { + ALOGE ("%s: fail disable; error=0x%X", __FUNCTION__, stat); + } + } + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + sAbortConnlessWait = true; + nativeLlcpConnectionlessSocket_abortWait(); + sIsNfaEnabled = false; + sDiscoveryEnabled = false; + sIsDisabling = false; + sIsSecElemSelected = false; + + { + //unblock NFA_EnablePolling() and NFA_DisablePolling() + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + sNfaEnableDisablePollingEvent.notifyOne (); + } + + NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); + theInstance.Finalize(); + + ALOGD ("%s: exit", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCreateLlcpSocket +** +** Description: Create a LLCP connection-oriented socket. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** miu: Maximum information unit. +** rw: Receive window size. +** linearBufferLength: Max buffer size. +** +** Returns: NativeLlcpSocket Java object. +** +*******************************************************************************/ +static jobject nfcManager_doCreateLlcpSocket (JNIEnv* e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) +{ + ALOGD ("%s: enter; sap=%d; miu=%d; rw=%d; buffer len=%d", __FUNCTION__, nSap, miu, rw, linearBufferLength); + jobject clientSocket = NULL; + jclass clsNativeLlcpSocket; + jfieldID f; + tBRCM_JNI_HANDLE jniHandle = gNextJniHandle++; + bool stat = false; + + stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw); + + /* Create new NativeLlcpSocket object */ + if (nfc_jni_cache_object_local(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1) + { + ALOGE ("%s: fail Llcp socket creation", __FUNCTION__); + goto TheEnd; + } + + /* Get NativeConnectionless class object */ + clsNativeLlcpSocket = e->GetObjectClass (clientSocket); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail get class object", __FUNCTION__); + goto TheEnd; + } + + /* Set socket SAP */ + f = e->GetFieldID (clsNativeLlcpSocket, "mSap", "I"); + e->SetIntField (clientSocket, f, (jint) nSap); + + /* Set socket handle */ + f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I"); + e->SetIntField (clientSocket, f, (jint) jniHandle); + + /* Set socket MIU */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I"); + e->SetIntField (clientSocket, f, (jint) miu); + + /* Set socket RW */ + f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I"); + e->SetIntField (clientSocket, f, (jint) rw); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return clientSocket; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCreateLlcpConnectionlessSocket +** +** Description: Create a connection-less socket. +** e: JVM environment. +** o: Java object. +** nSap: Service access point. +** sn: Service name. +** +** Returns: NativeLlcpConnectionlessSocket Java object. +** +*******************************************************************************/ +static jobject nfcManager_doCreateLlcpConnectionlessSocket (JNIEnv *e, jobject o, jint nSap, jstring sn) +{ + ALOGD ("%s: nSap=0x%X", __FUNCTION__, nSap); + return NULL; +} + + +/******************************************************************************* +** +** Function: nfcManager_doGetSecureElementList +** +** Description: Get a list of secure element handles. +** e: JVM environment. +** o: Java object. +** +** Returns: List of secure element handles. +** +*******************************************************************************/ +static jintArray nfcManager_doGetSecureElementList(JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return SecureElement::getInstance().getListOfEeHandles (e); +} + + +/******************************************************************************* +** +** Function: nfcManager_doSelectSecureElement +** +** Description: NFC controller starts routing data in listen mode. +** e: JVM environment. +** o: Java object. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = true; + + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); + + // Stop RF Discovery. + startRfDiscovery (false); + + if (sIsSecElemSelected) + { + ALOGD ("%s: already selected", __FUNCTION__); + goto TheEnd; + } + + stat = SecureElement::getInstance().activate (0xABCDEF); + if (stat) + SecureElement::getInstance().routeToSecureElement (); + sIsSecElemSelected = true; + +TheEnd: + // Restart RF Discovery. + startRfDiscovery (true); + + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: nfcManager_doDeselectSecureElement +** +** Description: NFC controller stops routing data in listen mode. +** e: JVM environment. +** o: Java object. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + bool stat = false; + bool isPowerLevelChanged = false; + + if (! sIsSecElemSelected) + { + ALOGE ("%s: already deselected", __FUNCTION__); + goto TheEnd; + } + + if (PowerSwitch::getInstance ().getLevel() == PowerSwitch::LOW_POWER) + { + ALOGD ("%s: do not deselect while power is OFF", __FUNCTION__); + sIsSecElemSelected = false; + goto TheEnd; + } + + stat = SecureElement::getInstance().routeToDefault (); + sIsSecElemSelected = false; + + //if controller is not routing to sec elems AND there is no pipe connected, + //then turn off the sec elems + if (SecureElement::getInstance().isBusy() == false) + SecureElement::getInstance().deactivate (0xABCDEF); + +TheEnd: + //if power level was changed at the top of this method, + //then restore to low power + if (isPowerLevelChanged || (!PowerSwitch::getInstance().isScreenOn() && (sDiscoveryEnabled == false)) ) + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: isPeerToPeer +** +** Description: Whether the activation data indicates the peer supports NFC-DEP. +** activated: Activation data. +** +** Returns: True if the peer supports NFC-DEP. +** +*******************************************************************************/ +static bool isPeerToPeer (tNFA_ACTIVATED& activated) +{ + return activated.activate_ntf.protocol == NFA_PROTOCOL_NFC_DEP; +} + + +/******************************************************************************* +** +** Function: nfcManager_doCheckLlcp +** +** Description: Not used. +** +** Returns: True +** +*******************************************************************************/ +static jboolean nfcManager_doCheckLlcp(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doActivateLlcp +** +** Description: Not used. +** +** Returns: True +** +*******************************************************************************/ +static jboolean nfcManager_doActivateLlcp(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doAbort +** +** Description: Not used. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doAbort(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: nfcManager_doDownload +** +** Description: Not used. +** +** Returns: True +** +*******************************************************************************/ +static jboolean nfcManager_doDownload(JNIEnv *e, jobject o) +{ + ALOGD("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nfcManager_doResetTimeouts +** +** Description: Not used. +** +** Returns: None +** +*******************************************************************************/ +static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o) +{ + ALOGD ("%s: %d millisec", __FUNCTION__, DEFAULT_GENERAL_TRANS_TIMEOUT); + gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT; +} + + +/******************************************************************************* +** +** Function: nfcManager_doSetTimeout +** +** Description: Set timeout value. +** e: JVM environment. +** o: Java object. +** timeout: Timeout value. +** +** Returns: True if ok. +** +*******************************************************************************/ +static bool nfcManager_doSetTimeout(JNIEnv *e, jobject o, jint tech, jint timeout) +{ + if (timeout <= 0) + { + ALOGE("%s: Timeout must be positive.",__FUNCTION__); + return false; + } + + ALOGD ("%s: timeout=%d", __FUNCTION__, timeout); + gGeneralTransceiveTimeout = timeout; + return true; +} + + +/******************************************************************************* +** +** Function: nfcManager_doGetTimeout +** +** Description: Get timeout value. +** e: JVM environment. +** o: Java object. +** tech: Not used. +** +** Returns: Timeout value. +** +*******************************************************************************/ +static jint nfcManager_doGetTimeout(JNIEnv *e, jobject o, jint tech) +{ + ALOGD ("%s: timeout=%d", __FUNCTION__, gGeneralTransceiveTimeout); + return gGeneralTransceiveTimeout; +} + + +/******************************************************************************* +** +** Function: nfcManager_doDump +** +** Description: Not used. +** e: JVM environment. +** o: Java object. +** +** Returns: Text dump. +** +*******************************************************************************/ +static jstring nfcManager_doDump(JNIEnv *e, jobject o) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", /*libnfc_llc_error_count*/ 0); + return e->NewStringUTF(buffer); +} + + +/******************************************************************************* +** +** Function: nfcManager_doSetP2pInitiatorModes +** +** Description: Set P2P initiator's activation modes. +** e: JVM environment. +** o: Java object. +** modes: Active and/or passive modes. The values are specified +** in external/libnfc-nxp/inc/phNfcTypes.h. See +** enum phNfc_eP2PMode_t. +** +** Returns: None. +** +*******************************************************************************/ +static void nfcManager_doSetP2pInitiatorModes (JNIEnv *e, jobject o, jint modes) +{ + ALOGD ("%s: modes=0x%X", __FUNCTION__, modes); + //this function is not called by the NFC service nor exposed by public API. +} + + +/******************************************************************************* +** +** Function: nfcManager_doSetP2pTargetModes +** +** Description: Set P2P target's activation modes. +** e: JVM environment. +** o: Java object. +** modes: Active and/or passive modes. +** +** Returns: None. +** +*******************************************************************************/ +static void nfcManager_doSetP2pTargetModes (JNIEnv *e, jobject o, jint modes) +{ + ALOGD ("%s: modes=0x%X", __FUNCTION__, modes); + //this function is not called by the NFC service nor exposed by public API. +} + +/******************************************************************************* +** +** Function nfcManager_doSetScreenState +** +** Description Forward the Screen On/Off state to native code for enhanced +** power saving mode. +** +** Returns true +** +*******************************************************************************/ +jboolean nfcManager_doSetScreenState(JNIEnv *e, jobject o, jboolean screenState) +{ + ALOGD ("%s(%d)", __FUNCTION__, screenState); + PowerSwitch::getInstance().setScreenState(screenState == JNI_TRUE); + return JNI_TRUE; +} + +/***************************************************************************** +** +** JNI functions for android-4.0.1_r1 +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doDownload", "()Z", + (void *)nfcManager_doDownload}, + + {"initializeNativeStructure", "()Z", + (void*) nfcManager_initNativeStruc}, + + {"doInitialize", "()Z", + (void*) nfcManager_doInitialize}, + + {"doDeinitialize", "()Z", + (void*) nfcManager_doDeinitialize}, + + {"enableDiscovery", "()V", + (void*) nfcManager_enableDiscovery}, + + {"doGetSecureElementList", "()[I", + (void *)nfcManager_doGetSecureElementList}, + + {"doSelectSecureElement", "()V", + (void *)nfcManager_doSelectSecureElement}, + + {"doDeselectSecureElement", "()V", + (void *)nfcManager_doDeselectSecureElement}, + + {"doCheckLlcp", "()Z", + (void *)nfcManager_doCheckLlcp}, + + {"doActivateLlcp", "()Z", + (void *)nfcManager_doActivateLlcp}, + + {"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;", + (void *)nfcManager_doCreateLlcpConnectionlessSocket}, + + {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;", + (void*) nfcManager_doCreateLlcpServiceSocket}, + + {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", + (void*) nfcManager_doCreateLlcpSocket}, + + {"doGetLastError", "()I", + (void*) nfcManager_doGetLastError}, + + {"disableDiscovery", "()V", + (void*) nfcManager_disableDiscovery}, + + {"doSetTimeout", "(II)Z", + (void *)nfcManager_doSetTimeout}, + + {"doGetTimeout", "(I)I", + (void *)nfcManager_doGetTimeout}, + + {"doResetTimeouts", "()V", + (void *)nfcManager_doResetTimeouts}, + + {"doAbort", "()V", + (void *)nfcManager_doAbort}, + + {"doSetP2pInitiatorModes", "(I)V", + (void *)nfcManager_doSetP2pInitiatorModes}, + + {"doSetP2pTargetModes", "(I)V", + (void *)nfcManager_doSetP2pTargetModes}, + + {"doDump", "()Ljava/lang/String;", + (void *)nfcManager_doDump}, + + {"doSetScreenState", "(Z)Z", + (void *)nfcManager_doSetScreenState}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeNfcManager +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeNfcManager (JNIEnv *e) +{ + GetNumValue (NAME_JNI_VERSION, &gJniVersion, sizeof(gJniVersion)); + ALOGD ("%s: enter, %s=%lu", __FUNCTION__, NAME_JNI_VERSION, gJniVersion); + PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL); + ALOGD ("%s: exit", __FUNCTION__); + return jniRegisterNativeMethods (e, gNativeNfcManagerClassName, gMethods, NELEM (gMethods)); +} + + +/******************************************************************************* +** +** Function: startRfDiscovery +** +** Description: Ask stack to start polling and listening for devices. +** isStart: Whether to start. +** +** Returns: None +** +*******************************************************************************/ +void startRfDiscovery(bool isStart) +{ + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + tNFA_STATUS status = NFA_STATUS_FAILED; + + ALOGD ("%s: is start=%d", __FUNCTION__, isStart); + + status = isStart ? NFA_StartRfDiscovery () : NFA_StopRfDiscovery (); + if (status == NFA_STATUS_OK) + { + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_RF_DISCOVERY_xxxx_EVT + } + else + { + ALOGE ("%s: Failed to start/stop RF discovery; error=0x%X", __FUNCTION__, status); + } +} + + +/******************************************************************************* +** +** Function: doStartupConfig +** +** Description: Configure the NFC controller. +** +** Returns: None +** +*******************************************************************************/ +void doStartupConfig() +{ + unsigned long num = 0; + struct nfc_jni_native_data *nat = getNative(0, 0); + + // Enable the "RC workaround" to allow our stack/firmware to work with a retail + // Nexus S that causes IOP issues. Only enable if value exists and set to 1. + if (GetNumValue(NAME_USE_NXP_P2P_RC_WORKAROUND, &num, sizeof(num)) && (num == 1)) + { +#if (NCI_VERSION > NCI_VERSION_20791B0) + UINT8 nfa_dm_rc_workaround[] = { 0x03, 0x0f, 0xab }; +#else + UINT8 nfa_dm_rc_workaround[] = { 0x01, 0x0f, 0xab, 0x01 }; +#endif + + ALOGD ("%s: Configure RC work-around", __FUNCTION__); + NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]); + } + + // If polling for Active mode, set the ordering so that we choose Active over Passive mode first. + if (nat && (nat->tech_mask & (NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE))) + { + UINT8 act_mode_order_param[] = { 0x01 }; + NFA_SetConfig(NCI_PARAM_ID_ACT_ORDER, sizeof(act_mode_order_param), &act_mode_order_param[0]); + } + + // Set configuration to allow UICC to Power off if there is no traffic. + if (GetNumValue(NAME_UICC_IDLE_TIMEOUT, &num, sizeof(num)) && (num != 0)) + { + // 61 => The least significant bit of this byte enables the power off when Idle mode. + // 00 87 93 03 == > These 4 bytes form a 4 byte value which decides the idle timeout(in us) + // value to trigger the uicc deactivation. + // e.g. in current example its value is 0x3938700 i.e. 60000000 is 60 seconds. + UINT8 swpcfg_param[] = { 0x61, 0x00, 0x82, 0x04, 0x20, 0xA1, 0x07, 0x00, + 0x90, 0xD0, 0x03, 0x00, 0x00, 0x87, 0x93, 0x03 }; + + ALOGD ("%s: Configure UICC idle-timeout to %lu ms", __FUNCTION__, num); + + // Set the timeout from the .conf file value. + num *= 1000; + UINT8 * p = &swpcfg_param[12]; + UINT32_TO_STREAM(p, num) + + NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]); + } + + // Set antenna tuning configuration if configured. +#define PREINIT_DSP_CFG_SIZE 30 + UINT8 preinit_dsp_param[PREINIT_DSP_CFG_SIZE]; + + if (GetStrValue(NAME_PREINIT_DSP_CFG, (char*)&preinit_dsp_param[0], sizeof(preinit_dsp_param))) + { + NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_param[0]); + } +} + + +/******************************************************************************* +** +** Function: nfcManager_isNfcActive +** +** Description: Used externaly to determine if NFC is active or not. +** +** Returns: 'true' if the NFC stack is running, else 'false'. +** +*******************************************************************************/ +bool nfcManager_isNfcActive() +{ + return sIsNfaEnabled; +} + + +/******************************************************************************* +** +** Function: nfaBrcmInitCallback +** +** Description: Callback function for application to start device initialization. +** When platform-specific initialization is completed, +** NCI_BrcmDevInitDone() must be called to proceed with stack start up. +** +** Returns: None. +** +*******************************************************************************/ +void nfaBrcmInitCallback (UINT32 brcm_hw_id) +{ + nfa_app_post_nci_reset (); +} + + +} /* namespace android */ + diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp new file mode 100755 index 0000000..7a92b44 --- /dev/null +++ b/nci/jni/NativeNfcTag.cpp @@ -0,0 +1,1554 @@ +/* + * Copyright (C) 2011 Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "NfcJniUtil.h" +#include "NfcTag.h" +#include "config.h" +#include "Mutex.h" +#include "IntervalTimer.h" + +extern "C" +{ + #include "nfa_api.h" + #include "nfa_rw_api.h" + #include "ndef_utils.h" + #include "rw_api.h" +} +namespace android +{ + extern nfc_jni_native_data* getNative(JNIEnv *e, jobject o); + extern char* gNativeNfcTagClassName; + extern bool nfcManager_isNfcActive(); + extern int gGeneralTransceiveTimeout; +} +extern long gJniVersion; + + +/***************************************************************************** +** +** public variables and functions +** +*****************************************************************************/ +namespace android +{ + bool gIsTagDeactivating = false; // flag for nfa callback indicating we are deactivating for RF interface switch + bool gIsSelectingRfInterface = false; // flag for nfa callback indicating we are selecting for RF interface switch +} + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ +namespace android +{ + + +// Pre-defined tag type values. These must match the values in +// framework Ndef.java for Google public NFC API. +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 + +#define STATUS_CODE_TARGET_LOST 146 // this error code comes from the service + +static uint32_t sCheckNdefCurrentSize = 0; +static tNFA_STATUS sCheckNdefStatus = 0; //whether tag already contains a NDEF message +static bool sCheckNdefCapable = false; //whether tag has NDEF capability +static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; +static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP; +static uint8_t* sTransceiveData = NULL; +static uint32_t sTransceiveDataLen = 0; +static bool sWaitingForTransceive = false; +static bool sNeedToSwitchRf = false; +static Mutex sRfInterfaceMutex; +static uint32_t sReadDataLen = 0; +static uint8_t* sReadData = NULL; +static bool sIsReadingNdefMessage = false; +static SyncEvent sReadEvent; +static sem_t sWriteSem; +static sem_t sFormatSem; +static SyncEvent sTransceiveEvent; +static SyncEvent sReconnectEvent; +static sem_t sCheckNdefSem; +static sem_t sPresenceCheckSem; +static sem_t sMakeReadonlySem; +static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back to ISO_DEP frame interface +static jboolean sWriteOk = JNI_FALSE; +static jboolean sWriteWaitingForComplete = JNI_FALSE; +static bool sFormatOk = false; +static jboolean sConnectOk = JNI_FALSE; +static jboolean sConnectWaitingForComplete = JNI_FALSE; +static bool sGotDeactivate = false; +static uint32_t sCheckNdefMaxSize = 0; +static bool sCheckNdefCardReadOnly = false; +static jboolean sCheckNdefWaitingForComplete = JNI_FALSE; +static int sCountTagAway = 0; //count the consecutive number of presence-check failures +static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED; +static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE; + +static int reSelect (tNFA_INTF_TYPE rfInterface); +static bool switchRfInterface(tNFA_INTF_TYPE rfInterface); + + +/******************************************************************************* +** +** Function: nativeNfcTag_abortWaits +** +** Description: Unblock all thread synchronization objects. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_abortWaits () +{ + ALOGD ("%s", __FUNCTION__); + { + SyncEventGuard g (sReadEvent); + sReadEvent.notifyOne (); + } + sem_post (&sWriteSem); + sem_post (&sFormatSem); + { + SyncEventGuard g (sTransceiveEvent); + sTransceiveEvent.notifyOne (); + } + { + SyncEventGuard g (sReconnectEvent); + sReconnectEvent.notifyOne (); + } + + sem_post (&sCheckNdefSem); + sem_post (&sPresenceCheckSem); + sem_post (&sMakeReadonlySem); +} + + +/******************************************************************************* +** +** Function: switchBackTimerProc +** +** Description: Callback function for interval timer. +** +** Returns: None +** +*******************************************************************************/ +static void switchBackTimerProc (union sigval) +{ + ALOGD ("%s", __FUNCTION__); + switchRfInterface(NFA_INTERFACE_ISO_DEP); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doReadCompleted +** +** Description: Receive the completion status of read operation. Called by +** NFA_READ_CPLT_EVT. +** status: Status of operation. +** +** Returns: None +** +*******************************************************************************/ +//called by NFA_READ_CPLT_EVT when NDEF message has been completely read +void nativeNfcTag_doReadCompleted (tNFA_STATUS status) +{ + ALOGD ("%s: status=0x%X; is reading=%u", __FUNCTION__, status, sIsReadingNdefMessage); + + if (sIsReadingNdefMessage == false) + return; //not reading NDEF message right now, so just return + + if (status != NFA_STATUS_OK) + { + sReadDataLen = 0; + if (sReadData) + free (sReadData); + sReadData = NULL; + } + SyncEventGuard g (sReadEvent); + sReadEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: ndefHandlerCallback +** +** Description: Receive NDEF-message related events from stack. +** event: Event code. +** p_data: Event data. +** +** Returns: None +** +*******************************************************************************/ +static void ndefHandlerCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *eventData) +{ + ALOGD ("%s: event=%u, eventData=%p", __FUNCTION__, event, eventData); + + switch (event) + { + case NFA_NDEF_REGISTER_EVT: + { + tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg; + ALOGD ("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X", __FUNCTION__, ndef_reg.status, ndef_reg.ndef_type_handle); + sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle; + } + break; + + case NFA_NDEF_DATA_EVT: + { + ALOGD ("%s: NFA_NDEF_DATA_EVT; data_len = %lu", __FUNCTION__, eventData->ndef_data.len); + sReadDataLen = eventData->ndef_data.len; + sReadData = (uint8_t*) malloc (sReadDataLen); + memcpy (sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len); + } + break; + + default: + ALOGE ("%s: Unknown event %u ????", __FUNCTION__, event); + break; + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doRead +** +** Description: Read the NDEF message on the tag. +** e: JVM environment. +** o: Java object. +** +** Returns: NDEF message. +** +*******************************************************************************/ +static jbyteArray nativeNfcTag_doRead (JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + tNFA_STATUS status = NFA_STATUS_FAILED; + jbyteArray buf = NULL; + + sReadDataLen = 0; + if (sReadData != NULL) + { + free (sReadData); + sReadData = NULL; + } + + if (sCheckNdefCurrentSize > 0) + { + SyncEventGuard g (sReadEvent); + sIsReadingNdefMessage = true; + status = NFA_RwReadNDef (); + sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT + sIsReadingNdefMessage = false; + + if (sReadDataLen > 0) //if stack actually read data from the tag + { + ALOGD ("%s: read %u bytes", __FUNCTION__, sReadDataLen); + buf = e->NewByteArray (sReadDataLen); + e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData); + } + } + else + { + ALOGD ("%s: create emtpy buffer", __FUNCTION__); + static uint8_t* empty = (uint8_t*) ""; + sReadDataLen = 0; + sReadData = (uint8_t*) malloc (1); + buf = e->NewByteArray (sReadDataLen); + e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData); + } + + if (sReadData) + { + free (sReadData); + sReadData = NULL; + } + sReadDataLen = 0; + + ALOGD ("%s: exit", __FUNCTION__); + return buf; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doWriteStatus +** +** Description: Receive the completion status of write operation. Called +** by NFA_WRITE_CPLT_EVT. +** isWriteOk: Status of operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doWriteStatus (jboolean isWriteOk) +{ + if (sWriteWaitingForComplete != JNI_FALSE) + { + sWriteWaitingForComplete = JNI_FALSE; + sWriteOk = isWriteOk; + sem_post (&sWriteSem); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_formatStatus +** +** Description: Receive the completion status of format operation. Called +** by NFA_FORMAT_CPLT_EVT. +** isOk: Status of operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_formatStatus (bool isOk) +{ + sFormatOk = isOk; + sem_post (&sFormatSem); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doWrite +** +** Description: Write a NDEF message to the tag. +** e: JVM environment. +** o: Java object. +** buf: Contains a NDEF message. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doWrite (JNIEnv *e, jobject o, jbyteArray buf) +{ + jboolean result = JNI_FALSE; + tNFA_STATUS status = 0; + UINT32 len = 0; + UINT8* p_data = NULL; + const int maxBufferSize = 1024; + UINT8 buffer[maxBufferSize] = { 0 }; + UINT32 curDataSize = 0; + + len = (UINT32) e->GetArrayLength (buf); + p_data = (UINT8*) e->GetByteArrayElements (buf, NULL); + + ALOGD ("%s: enter; len = %lu", __FUNCTION__, len); + + /* Create the write semaphore */ + if (sem_init (&sWriteSem, 0, 0) == -1) + { + ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + sWriteWaitingForComplete = JNI_TRUE; + if (sCheckNdefStatus == NFA_STATUS_FAILED) + { + //if tag does not contain a NDEF message + //and tag is capable of storing NDEF message + if (sCheckNdefCapable) + { + ALOGD ("%s: try format", __FUNCTION__); + sem_init (&sFormatSem, 0, 0); + sFormatOk = false; + status = NFA_RwFormatTag (); + sem_wait (&sFormatSem); + sem_destroy (&sFormatSem); + if (sFormatOk == false) //if format operation failed + goto TheEnd; + } + ALOGD ("%s: try write", __FUNCTION__); + status = NFA_RwWriteNDef (p_data, len); + } + else if (len == 0) + { + //if (NXP TagWriter wants to erase tag) then create and write an empty ndef message + NDEF_MsgInit (buffer, maxBufferSize, &curDataSize); + status = NDEF_MsgAddRec (buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY, NULL, 0, NULL, 0, NULL, 0); + ALOGD ("%s: create empty ndef msg; status=%u; size=%lu", __FUNCTION__, status, curDataSize); + status = NFA_RwWriteNDef (buffer, curDataSize); + } + else + { + ALOGD ("%s: NFA_RwWriteNDef", __FUNCTION__); + status = NFA_RwWriteNDef (p_data, len); + } + + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: write/format error=%d", __FUNCTION__, status); + goto TheEnd; + } + + /* Wait for write completion status */ + sWriteOk = false; + if (sem_wait (&sWriteSem)) + { + ALOGE ("%s: wait semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + result = sWriteOk; + +TheEnd: + /* Destroy semaphore */ + if (sem_destroy (&sWriteSem)) + { + ALOGE ("%s: failed destroy semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + sWriteWaitingForComplete = JNI_FALSE; + ALOGD ("%s: exit; result=%d", __FUNCTION__, result); + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doConnectStatus +** +** Description: Receive the completion status of connect operation. +** isConnectOk: Status of the operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doConnectStatus (jboolean isConnectOk) +{ + if (sConnectWaitingForComplete != JNI_FALSE) + { + sConnectWaitingForComplete = JNI_FALSE; + sConnectOk = isConnectOk; + SyncEventGuard g (sReconnectEvent); + sReconnectEvent.notifyOne (); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doDeactivateStatus +** +** Description: Receive the completion status of deactivate operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doDeactivateStatus (int status) +{ + sGotDeactivate = (status == 0); + + SyncEventGuard g (sReconnectEvent); + sReconnectEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doConnect +** +** Description: Connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: Must return NXP status code, which NFC service expects. +** +*******************************************************************************/ +static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle) +{ + ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); + int i = targetHandle; + struct nfc_jni_native_data *nat = getNative (0, 0); + NfcTag& natTag = NfcTag::getInstance (); + sNeedToSwitchRf = false; + + if (i >= NfcTag::MAX_NUM_TECHNOLOGY) + { + ALOGE ("%s: Handle not found", __FUNCTION__); + return NFCSTATUS_FAILED; + } + + if (natTag.mTechLibNfcTypes[i] != NFC_PROTOCOL_ISO_DEP) + { + ALOGD ("%s() Nfc type = %d, do nothing for non ISO_DEP", __FUNCTION__, natTag.mTechLibNfcTypes[i]); + return NFCSTATUS_SUCCESS; + } + + if (natTag.mTechList[i] == TARGET_TYPE_ISO14443_3A || natTag.mTechList[i] == TARGET_TYPE_ISO14443_3B) + { + ALOGD ("%s: switching to tech: %d need to switch rf intf to frame", __FUNCTION__, natTag.mTechList[i]); + // connecting to NfcA or NfcB don't actually switch until/unless we get a transceive + sNeedToSwitchRf = true; + } + else + { + // connecting back to IsoDep or NDEF + return (switchRfInterface (NFA_INTERFACE_ISO_DEP) ? NFCSTATUS_SUCCESS : NFCSTATUS_FAILED); + } + + return NFCSTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function: reSelect +** +** Description: Deactivates the tag and re-selects it with the specified +** rf interface. +** +** Returns: status code, 0 on success, 1 on failure, +** 146 (defined in service) on tag lost +** +*******************************************************************************/ +static int reSelect (tNFA_INTF_TYPE rfInterface) +{ + ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface); + NfcTag& natTag = NfcTag::getInstance (); + + ALOGD ("%s: NFA_Deactivate()", __FUNCTION__); + tNFA_STATUS status; + int rVal = 1; + + do + { + SyncEventGuard g (sReconnectEvent); + gIsTagDeactivating = true; + sGotDeactivate = false; + if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) + { + ALOGE ("%s: NFA_Deactivate failed, status = %d", __FUNCTION__, status); + break; + } + + if (sReconnectEvent.wait (1000) == false) //if timeout occured + { + ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__); + } + + if (! NfcTag::getInstance ().isActivated ()) + { + rVal = STATUS_CODE_TARGET_LOST; + break; + } + + gIsTagDeactivating = false; + + SyncEventGuard g2 (sReconnectEvent); + + sConnectWaitingForComplete = JNI_TRUE; + ALOGD ("%s: NFA_Select()", __FUNCTION__); + gIsSelectingRfInterface = true; + if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface))) + { + ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status); + break; + } + + sConnectOk = false; + if (sReconnectEvent.wait (1000) == false) //if timeout occured + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + break; + } + ALOGD("%s: done waiting on NFA_Select() sConnectOk=%d", __FUNCTION__, sConnectOk); + if (! NfcTag::getInstance ().isActivated ()) + { + ALOGD("%s: Tag no longer active", __FUNCTION__); + rVal = STATUS_CODE_TARGET_LOST; + break; + } + rVal = (sConnectOk) ? 0 : 1; + } while (0); + + sConnectWaitingForComplete = JNI_FALSE; + gIsTagDeactivating = false; + gIsSelectingRfInterface = false; + return rVal; +} + +/******************************************************************************* +** +** Function: switchRfInterface +** +** Description: Switch controller's RF interface to frame, ISO-DEP, or NFC-DEP. +** rfInterface: Type of RF interface. +** +** Returns: True if ok. +** +*******************************************************************************/ +static bool switchRfInterface (tNFA_INTF_TYPE rfInterface) +{ + ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface); + NfcTag& natTag = NfcTag::getInstance (); + + if (natTag.mTechLibNfcTypes[0] != NFC_PROTOCOL_ISO_DEP) + { + ALOGD ("%s: protocol: %d not ISO_DEP, do nothing", __FUNCTION__, natTag.mTechLibNfcTypes[0]); + return true; + } + + sRfInterfaceMutex.lock (); + ALOGD ("%s: new rf intf = %d, cur rf intf = %d", __FUNCTION__, rfInterface, sCurrentRfInterface); + + bool rVal = true; + if (rfInterface != sCurrentRfInterface) + { + if (rVal = (0 == reSelect(rfInterface))) + { + sCurrentRfInterface = rfInterface; + } + } + + sRfInterfaceMutex.unlock (); + return rVal; +} + +/******************************************************************************* +** +** Function: nativeNfcTag_doConnect_z +** +** Description: Connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doConnect_z (JNIEnv *e, jobject o, jint targetHandle) +{ + jint result = nativeNfcTag_doConnect (e, o, targetHandle); + return result == NFCSTATUS_SUCCESS ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doReconnect +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: Status code. +** +*******************************************************************************/ +static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + + tNFA_INTF_TYPE intf = NFA_INTERFACE_FRAME; + NfcTag& natTag = NfcTag::getInstance (); + + // this is only supported for type 2 or 4 (ISO_DEP) tags + if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP) + intf = NFA_INTERFACE_ISO_DEP; + else if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_T2T) + intf = NFA_INTERFACE_FRAME; + else + { + return 0; // success + } + + return reSelect(intf); +} + +/******************************************************************************* +** +** Function: nativeNfcTag_doReconnect_z +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doReconnect_z (JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + //do nothing as the tag has already been activated + return JNI_TRUE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doHandleReconnect +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: Status code. +** +*******************************************************************************/ +static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHandle) +{ + ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); + return nativeNfcTag_doConnect (e, o, targetHandle); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doHandleReconnect_z +** +** Description: Re-connect to the tag in RF field. +** e: JVM environment. +** o: Java object. +** targetHandle: Handle of the tag. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doHandleReconnect_z (JNIEnv *e, jobject o, jint targetHandle) +{ + ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); + return nativeNfcTag_doConnect_z (e, o, targetHandle); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doDisconnect +** +** Description: Deactivate the RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doDisconnect (JNIEnv *e, jobject o) +{ + ALOGD ("%s: enter", __FUNCTION__); + struct nfc_jni_native_data *nat = getNative (0, 0); + tNFA_STATUS nfaStat = NFA_STATUS_OK; + + gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT; + + if (NfcTag::getInstance ().isActivated () == false) + { + ALOGD ("%s: tag already deactivated", __FUNCTION__); + goto TheEnd; + } + + nfaStat = NFA_Deactivate (FALSE); + if (nfaStat != NFA_STATUS_OK) + ALOGE ("%s: deactivate failed; error=0x%X", __FUNCTION__, nfaStat); + +TheEnd: + ALOGD ("%s: exit", __FUNCTION__); + return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doTranseiveStatus +** +** Description: Receive the completion status of transceive operation. +** buf: Contains tag's response. +** bufLen: Length of buffer. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doTranseiveStatus (uint8_t* buf, uint32_t bufLen) +{ + ALOGD ("%s: data len=%d, waiting for transceive: %d", __FUNCTION__, bufLen, sWaitingForTransceive); + if (!sWaitingForTransceive) + return; + + sTransceiveDataLen = 0; + if (bufLen) + { + if (NULL == (sTransceiveData = (uint8_t *) malloc (bufLen))) + { + ALOGD ("%s: memory allocation error", __FUNCTION__); + } + else + { + memcpy (sTransceiveData, buf, sTransceiveDataLen = bufLen); + } + } + + { + SyncEventGuard g (sTransceiveEvent); + sTransceiveEvent.notifyOne (); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doTransceive +** +** Description: Send raw data to the tag; receive tag's response. +** e: JVM environment. +** o: Java object. +** raw: Not used. +** statusTargetLost: Whether tag responds or times out. +** +** Returns: Response from tag. +** +*******************************************************************************/ +static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost) +{ + ALOGD ("%s: enter; raw=%u; timeout = %d", __FUNCTION__, raw, gGeneralTransceiveTimeout); + bool fNeedToSwitchBack = false; + nfc_jni_native_data *nat = getNative (0, 0); + bool waitOk = false; + uint8_t *buf = NULL; + uint32_t bufLen = 0; + jint *targetLost = NULL; + + if (! NfcTag::getInstance ().isActivated ()) + { + if (statusTargetLost) + { + targetLost = e->GetIntArrayElements (statusTargetLost, 0); + if (targetLost) + *targetLost = 1; //causes NFC service to throw TagLostException + e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); + } + ALOGD ("%s: tag not active", __FUNCTION__); + return NULL; + } + + NfcTag& natTag = NfcTag::getInstance (); + if (natTag.mNumTechList >= 2 && natTag.mTechList[0] == TARGET_TYPE_ISO14443_3A) + { + if (natTag.mTechList[1] == TARGET_TYPE_MIFARE_CLASSIC) + { + // MifareClassic tag, we do not support transeive for this + if (statusTargetLost) + { + targetLost = e->GetIntArrayElements (statusTargetLost, 0); + if (targetLost) + *targetLost = 2; //causes NFC service to throw IOException + e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); + } + ALOGD ("%s: transceive not supported for MifareClassic tag", __FUNCTION__); + return NULL; + } + } + + // get input buffer and length from java call + buf = (uint8_t *) e->GetByteArrayElements (data, NULL); + bufLen = (uint32_t) e->GetArrayLength (data); + + if (statusTargetLost) + { + targetLost = e->GetIntArrayElements (statusTargetLost, 0); + if (targetLost) + *targetLost = 0; //success, tag is still present + } + + sSwitchBackTimer.kill (); + jbyteArray result = NULL; + do + { + if (sNeedToSwitchRf) + { + // for ISO_DEP tags connected to NfcA or NfcB we need to be in FRAME interface + if (!switchRfInterface (NFA_INTERFACE_FRAME)) //NFA_INTERFACE_ISO_DEP + { + break; + } + fNeedToSwitchBack = true; + } + + sWaitingForTransceive = true; + sTransceiveDataLen = 0; + { + SyncEventGuard g (sTransceiveEvent); + tNFA_STATUS status = NFA_SendRawFrame (buf, bufLen); + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: fail send; error=%d", __FUNCTION__, status); + break; + } + waitOk = sTransceiveEvent.wait (gGeneralTransceiveTimeout); + } + + if (waitOk == false) //if timeout occured + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + if (targetLost) + *targetLost = 2; //causes NFC service to throw IOException + break; + } + + if (! NfcTag::getInstance ().isActivated ()) + { + ALOGE ("%s: already deactivated", __FUNCTION__); + if (targetLost) + *targetLost = 1; //causes NFC service to throw TagLostException + break; + } + + ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen); + if (sTransceiveDataLen) + { + // marshall data to java for return + result = e->NewByteArray (sTransceiveDataLen); + if (result != NULL) + { + e->SetByteArrayRegion (result, 0, sTransceiveDataLen, (jbyte *) sTransceiveData); + } + else + ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__); + + free (sTransceiveData); + sTransceiveData = NULL; + sTransceiveDataLen = 0; + } + } while (0); + + sWaitingForTransceive = false; + e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT); + if (targetLost) + e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); + + if (fNeedToSwitchBack) + { + // this timer proc will switch us back to ISO_DEP frame interface + sSwitchBackTimer.set (1500, switchBackTimerProc); + } + + ALOGD ("%s: exit", __FUNCTION__); + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doGetNdefType +** +** Description: Retrieve the type of tag. +** e: JVM environment. +** o: Java object. +** libnfcType: Type of tag represented by JNI. +** javaType: Not used. +** +** Returns: Type of tag represented by NFC Service. +** +*******************************************************************************/ +static jint nativeNfcTag_doGetNdefType (JNIEnv *e, jobject o, jint libnfcType, jint javaType) +{ + ALOGD ("%s: enter; libnfc type=%d; java type=%d", __FUNCTION__, libnfcType, javaType); + jint ndefType = NDEF_UNKNOWN_TYPE; + + // For NFA, libnfcType is mapped to the protocol value received + // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event. + switch (libnfcType) { + case NFA_PROTOCOL_T1T: + ndefType = NDEF_TYPE1_TAG; + break; + case NFA_PROTOCOL_T2T: + ndefType = NDEF_TYPE2_TAG;; + break; + case NFA_PROTOCOL_T3T: + ndefType = NDEF_TYPE3_TAG; + break; + case NFA_PROTOCOL_ISO_DEP: + ndefType = NDEF_TYPE4_TAG; + break; + case NFA_PROTOCOL_ISO15693: + ndefType = NDEF_UNKNOWN_TYPE; + break; + case NFA_PROTOCOL_INVALID: + ndefType = NDEF_UNKNOWN_TYPE; + break; + default: + ndefType = NDEF_UNKNOWN_TYPE; + break; + } + ALOGD ("%s: exit; ndef type=%d", __FUNCTION__, ndefType); + return ndefType; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doCheckNdefResult +** +** Description: Receive the result of checking whether the tag contains a NDEF +** message. Called by the NFA_NDEF_DETECT_EVT. +** status: Status of the operation. +** maxSize: Maximum size of NDEF message. +** currentSize: Current size of NDEF message. +** flags: Indicate various states. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint32_t currentSize, uint8_t flags) +{ + //this function's flags parameter is defined using the following macros + //in nfc/include/rw_api.h; + //#define RW_NDEF_FL_READ_ONLY 0x01 /* Tag is read only */ + //#define RW_NDEF_FL_FORMATED 0x02 /* Tag formated for NDEF */ + //#define RW_NDEF_FL_SUPPORTED 0x04 /* NDEF supported by the tag */ + //#define RW_NDEF_FL_UNKNOWN 0x08 /* Unable to find if tag is ndef capable/formated/read only */ + //#define RW_NDEF_FL_FORMATABLE 0x10 /* Tag supports format operation */ + + if (status == NFC_STATUS_BUSY) + { + ALOGE ("%s: stack is busy", __FUNCTION__); + return; + } + + if (!sCheckNdefWaitingForComplete) + { + ALOGE ("%s: not waiting", __FUNCTION__); + return; + } + + if (flags & RW_NDEF_FL_READ_ONLY) + ALOGD ("%s: flag read-only", __FUNCTION__); + if (flags & RW_NDEF_FL_FORMATED) + ALOGD ("%s: flag formatted for ndef", __FUNCTION__); + if (flags & RW_NDEF_FL_SUPPORTED) + ALOGD ("%s: flag ndef supported", __FUNCTION__); + if (flags & RW_NDEF_FL_UNKNOWN) + ALOGD ("%s: flag all unknown", __FUNCTION__); + if (flags & RW_NDEF_FL_FORMATABLE) + ALOGD ("%s: flag formattable", __FUNCTION__); + + sCheckNdefWaitingForComplete = JNI_FALSE; + sCheckNdefStatus = status; + sCheckNdefCapable = false; //assume tag is NOT ndef capable + if (sCheckNdefStatus == NFA_STATUS_OK) + { + //NDEF content is on the tag + sCheckNdefMaxSize = maxSize; + sCheckNdefCurrentSize = currentSize; + sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY; + sCheckNdefCapable = true; + } + else if (sCheckNdefStatus == NFA_STATUS_FAILED) + { + //no NDEF content on the tag + sCheckNdefMaxSize = 0; + sCheckNdefCurrentSize = 0; + sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY; + if ((flags & RW_NDEF_FL_UNKNOWN) == 0) //if stack understands the tag + { + if (flags & RW_NDEF_FL_SUPPORTED) //if tag is ndef capable + sCheckNdefCapable = true; + } + } + else + { + ALOGE ("%s: unknown status=0x%X", __FUNCTION__, status); + sCheckNdefMaxSize = 0; + sCheckNdefCurrentSize = 0; + sCheckNdefCardReadOnly = false; + } + sem_post (&sCheckNdefSem); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doCheckNdef +** +** Description: Does the tag contain a NDEF message? +** e: JVM environment. +** o: Java object. +** ndefInfo: NDEF info. +** +** Returns: Status code. +** +*******************************************************************************/ +static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo) +{ + tNFA_STATUS status = NFA_STATUS_FAILED; + jint* ndef = NULL; + + ALOGD ("%s: enter", __FUNCTION__); + + /* Create the write semaphore */ + if (sem_init (&sCheckNdefSem, 0, 0) == -1) + { + ALOGE ("%s: Check NDEF semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + if (NfcTag::getInstance ().isActivated () == false) + { + ALOGE ("%s: tag not present", __FUNCTION__); + goto TheEnd; + } + + ALOGD ("%s: try NFA_RwDetectNDef", __FUNCTION__); + sCheckNdefWaitingForComplete = JNI_TRUE; + status = NFA_RwDetectNDef (); + + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_RwDetectNDef failed, status = %d", __FUNCTION__, status); + goto TheEnd; + } + + /* Wait for check NDEF completion status */ + if (sem_wait (&sCheckNdefSem)) + { + ALOGE ("%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + if (sCheckNdefStatus == NFA_STATUS_OK) + { + //stack found a NDEF message on the tag + ndef = e->GetIntArrayElements (ndefInfo, 0); + if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T) + ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize (); + else + ndef[0] = sCheckNdefMaxSize; + if (sCheckNdefCardReadOnly) + ndef[1] = NDEF_MODE_READ_ONLY; + else + ndef[1] = NDEF_MODE_READ_WRITE; + e->ReleaseIntArrayElements (ndefInfo, ndef, 0); + status = NFA_STATUS_OK; + } + else if (sCheckNdefStatus == NFA_STATUS_FAILED) + { + //stack did not find a NDEF message on the tag; + ndef = e->GetIntArrayElements (ndefInfo, 0); + if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T) + ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize (); + else + ndef[0] = sCheckNdefMaxSize; + if (sCheckNdefCardReadOnly) + ndef[1] = NDEF_MODE_READ_ONLY; + else + ndef[1] = NDEF_MODE_READ_WRITE; + e->ReleaseIntArrayElements (ndefInfo, ndef, 0); + status = NFA_STATUS_FAILED; + } + else + { + ALOGD ("%s: unknown status 0x%X", __FUNCTION__, sCheckNdefStatus); + } + +TheEnd: + /* Destroy semaphore */ + if (sem_destroy (&sCheckNdefSem)) + { + ALOGE ("%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + sCheckNdefWaitingForComplete = JNI_FALSE; + ALOGD ("%s: exit; status=%u", __FUNCTION__, status); + return status; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doCheckNdef_z +** +** Description: Does the tag contain a NDEF message? +** e: JVM environment. +** o: Java object. +** ndefInfo: NDEF info. +** +** Returns: True if tag contains a NDEF message. +** +*******************************************************************************/ +static bool nativeNfcTag_doCheckNdef_z (JNIEnv *e, jobject o, jintArray ndefInfo) +{ + ALOGD ("%s: enter", __FUNCTION__); + jint result = nativeNfcTag_doCheckNdef (e, o, ndefInfo); + bool retval = (result == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; + ALOGD ("%s: exit; detected NDEF=%u", __FUNCTION__, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_resetPresenceCheck +** +** Description: Reset variables related to presence-check. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_resetPresenceCheck () +{ + sCountTagAway = 0; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doPresenceCheckResult +** +** Description: Receive the result of presence-check. +** status: Result of presence-check. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status) +{ + if (status == NFA_STATUS_OK) + sCountTagAway = 0; + else + sCountTagAway++; + if (sCountTagAway > 0) + ALOGD ("%s: sCountTagAway=%d", __FUNCTION__, sCountTagAway); + sem_post (&sPresenceCheckSem); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doPresenceCheck +** +** Description: Check if the tag is in the RF field. +** e: JVM environment. +** o: Java object. +** +** Returns: True if tag is in RF field. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doPresenceCheck (JNIEnv *e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + tNFA_STATUS status = NFA_STATUS_OK; + jboolean isPresent = JNI_FALSE; + + if (nfcManager_isNfcActive() == false) + { + ALOGD ("%s: NFC is no longer active.", __FUNCTION__); + return JNI_FALSE; + } + + if (NfcTag::getInstance ().isActivated () == false) + { + ALOGD ("%s: tag already deactivated", __FUNCTION__); + return JNI_FALSE; + } + + if (sem_init (&sPresenceCheckSem, 0, 0) == -1) + { + ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + status = NFA_RwPresenceCheck (); + if (status == NFA_STATUS_OK) + { + if (sem_wait (&sPresenceCheckSem)) + { + ALOGE ("%s: failed to wait (errno=0x%08x)", __FUNCTION__, errno); + } + else + { + isPresent = (sCountTagAway > 3) ? JNI_FALSE : JNI_TRUE; + } + } + + if (sem_destroy (&sPresenceCheckSem)) + { + ALOGE ("Failed to destroy check NDEF semaphore (errno=0x%08x)", errno); + } + + if (isPresent == JNI_FALSE) + ALOGD ("%s: tag absent ????", __FUNCTION__); + return isPresent; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doIsNdefFormatable +** +** Description: Can tag be formatted to store NDEF message? +** e: JVM environment. +** o: Java object. +** libNfcType: Type of tag. +** uidBytes: Tag's unique ID. +** pollBytes: Data from activation. +** actBytes: Data from activation. +** +** Returns: True if formattable. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doIsNdefFormatable (JNIEnv *e, + jobject o, jint libNfcType, jbyteArray uidBytes, jbyteArray pollBytes, + jbyteArray actBytes) +{ + jboolean isFormattable = JNI_FALSE; + + switch (NfcTag::getInstance().getProtocol()) + { + case NFA_PROTOCOL_T1T: + case NFA_PROTOCOL_ISO15693: + isFormattable = JNI_TRUE; + break; + + case NFA_PROTOCOL_T2T: + isFormattable = NfcTag::getInstance().isMifareUltralight() ? JNI_TRUE : JNI_FALSE; + } + ALOGD("%s: is formattable=%u", __FUNCTION__, isFormattable); + return isFormattable; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doIsIsoDepNdefFormatable +** +** Description: Is ISO-DEP tag formattable? +** e: JVM environment. +** o: Java object. +** pollBytes: Data from activation. +** actBytes: Data from activation. +** +** Returns: True if formattable. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doIsIsoDepNdefFormatable (JNIEnv *e, jobject o, jbyteArray pollBytes, jbyteArray actBytes) +{ + uint8_t uidFake[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + ALOGD ("%s", __FUNCTION__); + jbyteArray uidArray = e->NewByteArray (8); + e->SetByteArrayRegion (uidArray, 0, 8, (jbyte*) uidFake); + return nativeNfcTag_doIsNdefFormatable (e, o, 0, uidArray, pollBytes, actBytes); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doNdefFormat +** +** Description: Format a tag so it can store NDEF message. +** e: JVM environment. +** o: Java object. +** key: Not used. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doNdefFormat (JNIEnv *e, jobject o, jbyteArray key) +{ + ALOGD ("%s: enter", __FUNCTION__); + tNFA_STATUS status = NFA_STATUS_OK; + + sem_init (&sFormatSem, 0, 0); + sFormatOk = false; + status = NFA_RwFormatTag (); + if (status == NFA_STATUS_OK) + { + ALOGD ("%s: wait for completion", __FUNCTION__); + sem_wait (&sFormatSem); + status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED; + } + else + ALOGE ("%s: error status=%u", __FUNCTION__, status); + sem_destroy (&sFormatSem); + + ALOGD ("%s: exit", __FUNCTION__); + return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doMakeReadonlyResult +** +** Description: Receive the result of making a tag read-only. Called by the +** NFA_SET_TAG_RO_EVT. +** status: Status of the operation. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status) +{ + if (sMakeReadonlyWaitingForComplete != JNI_FALSE) + { + sMakeReadonlyWaitingForComplete = JNI_FALSE; + sMakeReadonlyStatus = status; + + sem_post (&sMakeReadonlySem); + } +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_doMakeReadonly +** +** Description: Make the tag read-only. +** e: JVM environment. +** o: Java object. +** key: Key to access the tag. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcTag_doMakeReadonly (JNIEnv *e, jobject o, jbyteArray key) +{ + jboolean result = JNI_FALSE; + tNFA_STATUS status; + + ALOGD ("%s", __FUNCTION__); + + /* Create the make_readonly semaphore */ + if (sem_init (&sMakeReadonlySem, 0, 0) == -1) + { + ALOGE ("%s: Make readonly semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); + return JNI_FALSE; + } + + sMakeReadonlyWaitingForComplete = JNI_TRUE; + + // Hard-lock the tag (cannot be reverted) + status = NFA_RwSetTagReadOnly(TRUE); + + if (status != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_RwSetTagReadOnly failed, status = %d", __FUNCTION__, status); + goto TheEnd; + } + + /* Wait for check NDEF completion status */ + if (sem_wait (&sMakeReadonlySem)) + { + ALOGE ("%s: Failed to wait for make_readonly semaphore (errno=0x%08x)", __FUNCTION__, errno); + goto TheEnd; + } + + if (sMakeReadonlyStatus == NFA_STATUS_OK) + { + result = JNI_TRUE; + } + +TheEnd: + /* Destroy semaphore */ + if (sem_destroy (&sMakeReadonlySem)) + { + ALOGE ("%s: Failed to destroy read_only semaphore (errno=0x%08x)", __FUNCTION__, errno); + } + sMakeReadonlyWaitingForComplete = JNI_FALSE; + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_registerNdefTypeHandler +** +** Description: Register a callback to receive NDEF message from the tag +** from the NFA_NDEF_DATA_EVT. +** +** Returns: None +** +*******************************************************************************/ +//register a callback to receive NDEF message from the tag +//from the NFA_NDEF_DATA_EVT; +void nativeNfcTag_registerNdefTypeHandler () +{ + ALOGD ("%s", __FUNCTION__); + sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; + NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *) "", 0, ndefHandlerCallback); +} + + +/******************************************************************************* +** +** Function: nativeNfcTag_deregisterNdefTypeHandler +** +** Description: No longer need to receive NDEF message from the tag. +** +** Returns: None +** +*******************************************************************************/ +void nativeNfcTag_deregisterNdefTypeHandler () +{ + ALOGD ("%s", __FUNCTION__); + NFA_DeregisterNDefTypeHandler (sNdefTypeHandlerHandle); + sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; +} + + +/***************************************************************************** +** +** JNI functions for Android 4.0.3 +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "(I)I", (void *)nativeNfcTag_doConnect}, + {"doDisconnect", "()Z", (void *)nativeNfcTag_doDisconnect}, + {"doReconnect", "()I", (void *)nativeNfcTag_doReconnect}, + {"doHandleReconnect", "(I)I", (void *)nativeNfcTag_doHandleReconnect}, + {"doTransceive", "([BZ[I)[B", (void *)nativeNfcTag_doTransceive}, + {"doGetNdefType", "(II)I", (void *)nativeNfcTag_doGetNdefType}, + {"doCheckNdef", "([I)I", (void *)nativeNfcTag_doCheckNdef}, + {"doRead", "()[B", (void *)nativeNfcTag_doRead}, + {"doWrite", "([B)Z", (void *)nativeNfcTag_doWrite}, + {"doPresenceCheck", "()Z", (void *)nativeNfcTag_doPresenceCheck}, + {"doIsIsoDepNdefFormatable", "([B[B)Z", (void *)nativeNfcTag_doIsIsoDepNdefFormatable}, + {"doNdefFormat", "([B)Z", (void *)nativeNfcTag_doNdefFormat}, + {"doMakeReadonly", "([B)Z", (void *)nativeNfcTag_doMakeReadonly}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeNfcTag +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeNfcTag (JNIEnv *e) +{ + GetNumValue (NAME_JNI_VERSION, &gJniVersion, sizeof(gJniVersion)); + ALOGD ("%s: enter, %s=%ld", __FUNCTION__, NAME_JNI_VERSION, gJniVersion); + ALOGD ("%s: exit; using %s", __FUNCTION__, gNativeNfcTagClassName); + return jniRegisterNativeMethods (e, gNativeNfcTagClassName, gMethods, NELEM (gMethods)); +} + + +} /* namespace android */ diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp new file mode 100644 index 0000000..16552a7 --- /dev/null +++ b/nci/jni/NativeP2pDevice.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NfcJniUtil.h" + + +namespace android +{ + + +extern char* gNativeP2pDeviceClassName; + + +static jboolean nativeP2pDeviceDoConnect (JNIEnv* e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return JNI_TRUE; +} + + +static jboolean nativeP2pDeviceDoDisconnect (JNIEnv* e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return JNI_TRUE; +} + + +static jbyteArray nativeP2pDeviceDoTransceive (JNIEnv* e, jobject o, jbyteArray data) +{ + ALOGD ("%s", __FUNCTION__); + return NULL; +} + + +static jbyteArray nativeP2pDeviceDoReceive (JNIEnv* e, jobject o) +{ + ALOGD ("%s", __FUNCTION__); + return NULL; +} + + +static jboolean nativeP2pDeviceDoSend (JNIEnv* e, jobject o, jbyteArray buf) +{ + ALOGD ("%s", __FUNCTION__); + return JNI_TRUE; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doConnect", "()Z", (void *) nativeP2pDeviceDoConnect}, + {"doDisconnect", "()Z", (void *) nativeP2pDeviceDoDisconnect}, + {"doTransceive", "([B)[B", (void *) nativeP2pDeviceDoTransceive}, + {"doReceive", "()[B", (void *) nativeP2pDeviceDoReceive}, + {"doSend", "([B)Z", (void *) nativeP2pDeviceDoSend}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeP2pDevice +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeP2pDevice (JNIEnv* e) +{ + return jniRegisterNativeMethods (e, gNativeP2pDeviceClassName, + gMethods, NELEM(gMethods)); +} + + +} // namepspace android diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp new file mode 100755 index 0000000..09091ed --- /dev/null +++ b/nci/jni/NativeSecureElement.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NfcJniUtil.h" +#include "SecureElement.h" +#include "nfa_brcm_api.h" + + +namespace android +{ + + +extern void com_android_nfc_NfcManager_disableDiscovery (JNIEnv* e, jobject o); +extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode); +extern char* gNativeNfcSecureElementClassName; +extern int gGeneralTransceiveTimeout; + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doOpenSecureElementConnection +** +** Description: Connect to the secure element. +** e: JVM environment. +** o: Java object. +** +** Returns: Handle of secure element. 0 is failure. +** +*******************************************************************************/ +static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, jobject o) +{ + ALOGD("%s: enter", __FUNCTION__); + bool stat = true; + jint secElemHandle = 0; + + //if controller is not routing AND there is no pipe connected, + //then turn on the sec elem + if (! SecureElement::getInstance().isBusy()) + stat = SecureElement::getInstance().activate(0); + + if (stat) + { + //establish a pipe to sec elem + stat = SecureElement::getInstance().connectEE(); + if (stat) + secElemHandle = SecureElement::getInstance().mActiveEeHandle; + else + SecureElement::getInstance().deactivate (0); + } + +TheEnd: + ALOGD("%s: exit; return handle=0x%X", __FUNCTION__, secElemHandle); + return secElemHandle; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doDisconnectSecureElementConnection +** +** Description: Disconnect from the secure element. +** e: JVM environment. +** o: Java object. +** handle: Handle of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIEnv* e, jobject o, jint handle) +{ + ALOGD("%s: enter; handle=0x%04x", __FUNCTION__, handle); + bool stat = false; + + stat = SecureElement::getInstance().disconnectEE (handle); + + //if controller is not routing AND there is no pipe connected, + //then turn off the sec elem + if (! SecureElement::getInstance().isBusy()) + SecureElement::getInstance().deactivate (handle); + + ALOGD("%s: exit", __FUNCTION__); + return stat ? JNI_TRUE : JNI_FALSE; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doTransceive +** +** Description: Send data to the secure element; retrieve response. +** e: JVM environment. +** o: Java object. +** handle: Secure element's handle. +** data: Data to send. +** +** Returns: Buffer of received data. +** +*******************************************************************************/ +static jbyteArray nativeNfcSecureElement_doTransceive (JNIEnv* e, jobject o, jint handle, jbyteArray data) +{ + UINT8* buf = NULL; + INT32 buflen = 0; + const INT32 recvBufferMaxSize = 1024; + UINT8 recvBuffer [recvBufferMaxSize]; + INT32 recvBufferActualSize = 0; + jbyteArray result = NULL; + + buf = (UINT8*) e->GetByteArrayElements (data, NULL); + buflen = e->GetArrayLength (data); + + ALOGD("%s: enter; handle=0x%X; buf len=%ld", __FUNCTION__, handle, buflen); + SecureElement::getInstance().transceive (buf, buflen, recvBuffer, recvBufferMaxSize, recvBufferActualSize, gGeneralTransceiveTimeout); + + //copy results back to java + result = e->NewByteArray (recvBufferActualSize); + if (result != NULL) + { + e->SetByteArrayRegion (result, 0, recvBufferActualSize, (jbyte *) recvBuffer); + } + + e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT); + ALOGD("%s: exit: recv len=%ld", __FUNCTION__, recvBufferActualSize); + return result; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doGetUid +** +** Description: Get the secure element's unique ID. +** e: JVM environment. +** o: Java object. +** handle: Handle of secure element. +** +** Returns: Secure element's unique ID. +** +*******************************************************************************/ +static jbyteArray nativeNfcSecureElement_doGetUid (JNIEnv* e, jobject o, jint handle) +{ + ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle); + jbyteArray secureElementUid = NULL; + + SecureElement::getInstance ().getUiccId (handle, secureElementUid); + + ALOGD("%s: exit", __FUNCTION__); + return secureElementUid; +} + + +/******************************************************************************* +** +** Function: nativeNfcSecureElement_doGetTechList +** +** Description: Get a list of technologies that the secure element supports. +** e: JVM environment. +** o: Java object. +** handle: Handle of secure element. +** +** Returns: Array of technologies. +** +*******************************************************************************/ +static jintArray nativeNfcSecureElement_doGetTechList (JNIEnv* e, jobject o, jint handle) +{ + ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle); + jintArray techList = NULL; + + SecureElement::getInstance().getTechnologyList (handle, techList); + + ALOGD("%s: exit", __FUNCTION__); + return techList; +} + + +/***************************************************************************** +** +** Description: JNI functions +** +*****************************************************************************/ +static JNINativeMethod gMethods[] = +{ + {"doNativeOpenSecureElementConnection", "()I", (void *) nativeNfcSecureElement_doOpenSecureElementConnection}, + {"doNativeDisconnectSecureElementConnection", "(I)Z", (void *) nativeNfcSecureElement_doDisconnectSecureElementConnection}, + {"doTransceive", "(I[B)[B", (void *) nativeNfcSecureElement_doTransceive}, + {"doGetUid", "(I)[B", (void *) nativeNfcSecureElement_doGetUid}, + {"doGetTechList", "(I)[I", (void *) nativeNfcSecureElement_doGetTechList}, +}; + + +/******************************************************************************* +** +** Function: register_com_android_nfc_NativeNfcSecureElement +** +** Description: Regisgter JNI functions with Java Virtual Machine. +** e: Environment of JVM. +** +** Returns: Status of registration. +** +*******************************************************************************/ +int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e) +{ + return jniRegisterNativeMethods(e, gNativeNfcSecureElementClassName, + gMethods, NELEM(gMethods)); +} + + +} // namespace android + diff --git a/nci/jni/NfcJniUtil.cpp b/nci/jni/NfcJniUtil.cpp new file mode 100755 index 0000000..d989188 --- /dev/null +++ b/nci/jni/NfcJniUtil.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NfcJniUtil.h" +#include + + +/******************************************************************************* +** +** Function: JNI_OnLoad +** +** Description: Register all JNI functions with Java Virtual Machine. +** jvm: Java Virtual Machine. +** reserved: Not used. +** +** Returns: JNI version. +** +*******************************************************************************/ +jint JNI_OnLoad (JavaVM *jvm, void *reserved) +{ + ALOGD ("%s: enter", __FUNCTION__); + JNIEnv *e = NULL; + + // Check JNI version + if (jvm->GetEnv ((void **) &e, JNI_VERSION_1_6)) + return JNI_ERR; + + if (android::register_com_android_nfc_NativeNfcManager (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpServiceSocket (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpSocket (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcTag (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeP2pDevice (e) == -1) + return JNI_ERR; + if (android::register_com_android_nfc_NativeNfcSecureElement (e) == -1) + return JNI_ERR; + ALOGD ("%s: exit", __FUNCTION__); + return JNI_VERSION_1_6; +} + + +namespace android +{ + + +/******************************************************************************* +** +** Function: nfc_jni_cache_object +** +** Description: +** +** Returns: Status code. +** +*******************************************************************************/ +int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj) +{ + jclass cls = NULL; + jobject obj = NULL; + jmethodID ctor = 0; + + cls = e->FindClass (className); + if(cls == NULL) + { + ALOGE ("%s: find class error", __FUNCTION__); + return -1; + } + + ctor = e->GetMethodID (cls, "", "()V"); + obj = e->NewObject (cls, ctor); + if (obj == NULL) + { + ALOGE ("%s: create object error", __FUNCTION__); + return -1; + } + + *cachedObj = e->NewGlobalRef (obj); + if (*cachedObj == NULL) + { + e->DeleteLocalRef (obj); + ALOGE ("%s: global ref error", __FUNCTION__); + return -1; + } + e->DeleteLocalRef (obj); + return 0; +} + + +/******************************************************************************* +** +** Function: nfc_jni_get_nfc_socket_handle +** +** Description: Get the value of "mHandle" member variable. +** e: JVM environment. +** o: Java object. +** +** Returns: Value of mHandle. +** +*******************************************************************************/ +int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o) +{ + jclass c = NULL; + jfieldID f = 0; + + c = e->GetObjectClass (o); + f = e->GetFieldID (c, "mHandle", "I"); + return e->GetIntField (o, f); +} + + +/******************************************************************************* +** +** Function: nfc_jni_get_nat +** +** Description: Get the value of "mNative" member variable. +** e: JVM environment. +** o: Java object. +** +** Returns: Pointer to the value of mNative. +** +*******************************************************************************/ +struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o) +{ + jclass c = NULL; + jfieldID f = 0; + + /* Retrieve native structure address */ + c = e->GetObjectClass(o); + f = e->GetFieldID(c, "mNative", "I"); + return (struct nfc_jni_native_data*)e->GetIntField(o, f); +} + + +} // namespace android diff --git a/nci/jni/NfcJniUtil.h b/nci/jni/NfcJniUtil.h new file mode 100755 index 0000000..18e75de --- /dev/null +++ b/nci/jni/NfcJniUtil.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#define LOG_TAG "BrcmNfcJni" +#include +#include +#include +#include +extern "C" +{ + #include + #include +} +#include // for property_get + + +/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ +#define DISCOVERY_MODE_TAG_READER 0 +#define DISCOVERY_MODE_NFCIP1 1 +#define DISCOVERY_MODE_CARD_EMULATION 2 +#define DISCOVERY_MODE_TABLE_SIZE 3 + +#define DISCOVERY_MODE_DISABLED 0 +#define DISCOVERY_MODE_ENABLED 1 + +#define MODE_P2P_TARGET 0 +#define MODE_P2P_INITIATOR 1 + + +/* Properties values */ +#define PROPERTY_LLCP_LTO 0 +#define PROPERTY_LLCP_MIU 1 +#define PROPERTY_LLCP_WKS 2 +#define PROPERTY_LLCP_OPT 3 +#define PROPERTY_NFC_DISCOVERY_A 4 +#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_F 6 +#define PROPERTY_NFC_DISCOVERY_15693 7 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 + + +/* Error codes */ +#define ERROR_BUFFER_TOO_SMALL -12 +#define ERROR_INSUFFICIENT_RESOURCES -9 + + +/* Pre-defined tag type values. These must match the values in + * Ndef.java in the framework. + */ +#define NDEF_UNKNOWN_TYPE -1 +#define NDEF_TYPE1_TAG 1 +#define NDEF_TYPE2_TAG 2 +#define NDEF_TYPE3_TAG 3 +#define NDEF_TYPE4_TAG 4 +#define NDEF_MIFARE_CLASSIC_TAG 101 + + +/* Pre-defined card read/write state values. These must match the values in + * Ndef.java in the framework. + */ +#define NDEF_MODE_READ_ONLY 1 +#define NDEF_MODE_READ_WRITE 2 +#define NDEF_MODE_UNKNOWN 3 + + +/* Name strings for target types. These *must* match the values in TagTechnology.java */ +#define TARGET_TYPE_UNKNOWN -1 +#define TARGET_TYPE_ISO14443_3A 1 +#define TARGET_TYPE_ISO14443_3B 2 +#define TARGET_TYPE_ISO14443_4 3 +#define TARGET_TYPE_FELICA 4 +#define TARGET_TYPE_ISO15693 5 +#define TARGET_TYPE_NDEF 6 +#define TARGET_TYPE_NDEF_FORMATABLE 7 +#define TARGET_TYPE_MIFARE_CLASSIC 8 +#define TARGET_TYPE_MIFARE_UL 9 + + +//define a few NXP error codes that NFC service expects; +//see external/libnfc-nxp/src/phLibNfcStatus.h; +//see external/libnfc-nxp/inc/phNfcStatus.h +#define NFCSTATUS_SUCCESS (0x0000) +#define NFCSTATUS_FAILED (0x00FF) + +//default general trasceive timeout in millisecond +#define DEFAULT_GENERAL_TRANS_TIMEOUT 1000 + +struct nfc_jni_native_data +{ + /* Thread handle */ + pthread_t thread; + int running; + + /* Our VM */ + JavaVM *vm; + int env_version; + + /* Reference to the NFCManager instance */ + jobject manager; + + /* Cached objects */ + jobject cached_NfcTag; + jobject cached_P2pDevice; + + /* Secure Element selected */ + int seId; + + /* LLCP params */ + int lto; + int miu; + int wks; + int opt; + + int tech_mask; + + /* Tag detected */ + jobject tag; + + int tHandle; + int tProtocols[16]; + int handles[16]; +}; + + +extern "C" +{ + jint JNI_OnLoad(JavaVM *jvm, void *reserved); +} + + +namespace android +{ + int nfc_jni_cache_object (JNIEnv *e, const char *clsname, jobject *cached_obj); + int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o); + struct nfc_jni_native_data* nfc_jni_get_nat (JNIEnv *e, jobject o); + int register_com_android_nfc_NativeNfcManager (JNIEnv *e); + int register_com_android_nfc_NativeNfcTag (JNIEnv *e); + int register_com_android_nfc_NativeP2pDevice (JNIEnv *e); + int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e); + int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv *e); + int register_com_android_nfc_NativeLlcpSocket (JNIEnv *e); + int register_com_android_nfc_NativeNfcSecureElement (JNIEnv *e); +} // namespace android + diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp new file mode 100755 index 0000000..c135014 --- /dev/null +++ b/nci/jni/NfcTag.cpp @@ -0,0 +1,1229 @@ +/***************************************************************************** +** +** Name: NfcTag.cpp +** +** Description: Tag-reading, tag-writing operations. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "NfcTag.h" +extern "C" +{ + #include "rw_int.h" +} + +extern long gJniVersion; + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyNdefMessageListeners; +} + + +/******************************************************************************* +** +** Function: NfcTag +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +NfcTag::NfcTag () +: mNativeData (NULL), + mIsActivated (false), + mProtocol(NFC_PROTOCOL_UNKNOWN), + mNumTechList (0), + mtT1tMaxMessageSize (0), + mReadCompletedStatus (NFA_STATUS_OK) +{ + memset (mTechList, 0, sizeof(mTechList)); + memset (mTechHandles, 0, sizeof(mTechHandles)); + memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); + memset (mTechParams, 0, sizeof(mTechParams)); + mLastKovioUidLen = 0; + memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN); +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get a reference to the singleton NfcTag object. +** +** Returns: Reference to NfcTag object. +** +*******************************************************************************/ +NfcTag& NfcTag::getInstance () +{ + static NfcTag tag; + return tag; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Reset member variables. +** native: Native data. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::initialize (nfc_jni_native_data* native) +{ + mNativeData = native; + mIsActivated = false; + mProtocol = NFC_PROTOCOL_UNKNOWN; + mNumTechList = 0; + mtT1tMaxMessageSize = 0; + mReadCompletedStatus = NFA_STATUS_OK; + resetTechnologies (); +} + + +/******************************************************************************* +** +** Function: abort +** +** Description: Unblock all operations. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::abort () +{ + SyncEventGuard g (mReadCompleteEvent); + mReadCompleteEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: isActivated +** +** Description: Is tag activated? +** +** Returns: True if tag is activated. +** +*******************************************************************************/ +bool NfcTag::isActivated () +{ + return mIsActivated; +} + + +/******************************************************************************* +** +** Function: getProtocol +** +** Description: Get the protocol of the current tag. +** +** Returns: Protocol number. +** +*******************************************************************************/ +tNFC_PROTOCOL NfcTag::getProtocol() +{ + return mProtocol; +} + +/******************************************************************************* +** +** Function TimeDiff +** +** Description Computes time difference in milliseconds. +** +** Returns Time difference in milliseconds +** +*******************************************************************************/ +UINT32 TimeDiff(timespec start, timespec end) +{ + timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) + { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } + else + { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + + return (temp.tv_sec * 1000) + (temp.tv_nsec / 1000000); +} + +/******************************************************************************* +** +** Function: IsSameKovio +** +** Description: Checks if tag activate is the same (UID) Kovio tag previously +** activated. This is needed due to a problem with some Kovio +** tags re-activating multiple times. +** activationData: data from activation. +** +** Returns: true if the activation is from the same tag previously +** activated, false otherwise +** +*******************************************************************************/ +bool NfcTag::IsSameKovio(tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::IsSameKovio"; + ALOGD ("%s: enter", fn); + tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf; + + if (rfDetail.protocol != NFC_PROTOCOL_KOVIO) + return false; + + memcpy (&(mTechParams[0]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + if (mTechParams [0].mode != NFC_DISCOVERY_TYPE_POLL_KOVIO) + return false; + + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + bool rVal = false; + if (mTechParams[0].param.pk.uid_len == mLastKovioUidLen) + { + if (memcmp(mLastKovioUid, &mTechParams [0].param.pk.uid, mTechParams[0].param.pk.uid_len) == 0) + { + //same tag + if (TimeDiff(mLastKovioTime, now) < 500) + { + // same tag within 500 ms, ignore activation + rVal = true; + } + } + } + + // save Kovio tag info + if (!rVal) + { + if ((mLastKovioUidLen = mTechParams[0].param.pk.uid_len) > NFC_KOVIO_MAX_LEN) + mLastKovioUidLen = NFC_KOVIO_MAX_LEN; + memcpy(mLastKovioUid, mTechParams[0].param.pk.uid, mLastKovioUidLen); + } + mLastKovioTime = now; + ALOGD ("%s: exit, is same Kovio=%d", fn, rVal); + return rVal; +} + +/******************************************************************************* +** +** Function: discoverTechnologies +** +** Description: Discover the technologies that NFC service needs by interpreting +** the data strucutures from the stack. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::discoverTechnologies (activation)"; + ALOGD ("%s: enter", fn); + tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf; + + mNumTechList = 0; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + + switch (rfDetail.protocol) + { + case NFC_PROTOCOL_T1T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + break; + + case NFC_PROTOCOL_T2T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + // could be MifFare UL or Classic or Kovio + { + // need to look at first byte of uid to find manuf. + tNFC_RF_TECH_PARAMS tech_params; + memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + + if ((tech_params.param.pa.nfcid1[0] == 0x04 && rfDetail.rf_tech_param.param.pa.sel_rsp == 0) || + rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 || + rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08) + { + //Mifare Ultralight or mifare Classic + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0) + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API + else + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API + } + } + break; + + case NFC_PROTOCOL_T3T: + mTechList [mNumTechList] = TARGET_TYPE_FELICA; + break; + + case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API + if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + } + else if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) || + (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + } + break; + + case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API + mTechList [mNumTechList] = TARGET_TYPE_ISO15693; + break; + + case NFC_PROTOCOL_KOVIO: + ALOGE ("%s: Kovio", fn); + mNumTechList--; // no tech classes for Kovio + break; + + default: + ALOGE ("%s: unknown protocol ????", fn); + mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN; + break; + } + + mNumTechList++; + for (int i=0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, + i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: discoverTechnologies +** +** Description: Discover the technologies that NFC service needs by interpreting +** the data strucutures from the stack. +** discoveryData: data from discovery events(s). +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::discoverTechnologies (tNFA_DISC_RESULT& discoveryData) +{ + static const char fn [] = "NfcTag::discoverTechnologies (discovery)"; + tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf; + + ALOGD ("%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn, discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList); + if (mNumTechList >= MAX_NUM_TECHNOLOGY) + { + ALOGE ("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY); + goto TheEnd; + } + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + + switch (discovery_ntf.protocol) + { + case NFC_PROTOCOL_T1T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + break; + + case NFC_PROTOCOL_T2T: + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + //type-2 tags are identitical to Mifare Ultralight, so Ultralight is also discovered + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + if (discovery_ntf.rf_tech_param.param.pa.sel_rsp == 0) + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API + else + mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API + + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + break; + + case NFC_PROTOCOL_T3T: + mTechList [mNumTechList] = TARGET_TYPE_FELICA; + break; + + case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API + if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + } + else if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) || + (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) + { + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; + mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); + } + break; + + case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API + mTechList [mNumTechList] = TARGET_TYPE_ISO15693; + break; + + default: + ALOGE ("%s: unknown protocol ????", fn); + mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN; + break; + } + + mNumTechList++; + if (discovery_ntf.more == FALSE) + { + for (int i=0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, + i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]); + } + } + +TheEnd: + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: createNativeNfcTag +** +** Description: Create a brand new Java NativeNfcTag object; +** fill the objects's member variables with data; +** notify NFC service; +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::createNativeNfcTag"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + jclass tag_cls = NULL; + jmethodID ctor = NULL; + jobject tag = NULL; + + //acquire a pointer to the Java virtual machine + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE("%s: jni env is null", fn); + goto TheEnd; + } + + tag_cls = e->GetObjectClass (mNativeData->cached_NfcTag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE("%s: failed to get class", fn); + goto TheEnd; + } + + //create a new Java NativeNfcTag object + ctor = e->GetMethodID (tag_cls, "", "()V"); + tag = e->NewObject (tag_cls, ctor); + + //fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes + fillNativeNfcTagMembers1 (e, tag_cls, tag); + + //fill NativeNfcTag's members: mHandle, mConnectedTechnology + fillNativeNfcTagMembers2 (e, tag_cls, tag, activationData); + + //fill NativeNfcTag's members: mTechPollBytes + fillNativeNfcTagMembers3 (e, tag_cls, tag, activationData); + + //fill NativeNfcTag's members: mTechActBytes + fillNativeNfcTagMembers4 (e, tag_cls, tag, activationData); + + //fill NativeNfcTag's members: mUid + fillNativeNfcTagMembers5 (e, tag_cls, tag, activationData); + + if (mNativeData->tag != NULL) { + e->DeleteGlobalRef (mNativeData->tag); + } + mNativeData->tag = e->NewGlobalRef (tag); + + //notify NFC service about this new tag + ALOGD ("%s: try notify nfc service", fn); + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyNdefMessageListeners, tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify nfc service", fn); + } + e->DeleteLocalRef (tag); + +TheEnd: + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers1 +** +** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes. +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers1"; + ALOGD ("%s", fn); + jfieldID f = NULL; + + //create objects that represent NativeNfcTag's member variables + jintArray techList = e->NewIntArray (mNumTechList); + jintArray handleList = e->NewIntArray (mNumTechList); + jintArray typeList = e->NewIntArray (mNumTechList); + + jint* technologies = e->GetIntArrayElements (techList, NULL); + jint* handles = e->GetIntArrayElements (handleList, NULL); + jint* types = e->GetIntArrayElements (typeList, NULL); + for (int i = 0; i < mNumTechList; i++) + { + mNativeData->tProtocols [i] = mTechLibNfcTypes [i]; + mNativeData->handles [i] = mTechHandles [i]; + technologies [i] = mTechList [i]; + handles [i] = mTechHandles [i]; + types [i] = mTechLibNfcTypes [i]; + } + e->ReleaseIntArrayElements (techList, technologies, 0); + e->ReleaseIntArrayElements (handleList, handles, 0); + e->ReleaseIntArrayElements (typeList, types, 0); + + f = e->GetFieldID (tag_cls, "mTechList", "[I"); + e->SetObjectField (tag, f, techList); + + f = e->GetFieldID (tag_cls, "mTechHandles", "[I"); + e->SetObjectField (tag, f, handleList); + + f = e->GetFieldID (tag_cls, "mTechLibNfcTypes", "[I"); + e->SetObjectField (tag, f, typeList); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers2 +** +** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology. +** The original Google's implementation is in set_target_pollBytes( +** in com_android_nfc_NativeNfcTag.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +//fill NativeNfcTag's members: mHandle, mConnectedTechnology +void NfcTag::fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers2"; + ALOGD ("%s", fn); + jfieldID f = NULL; + + f = e->GetFieldID (tag_cls, (gJniVersion >= 401) ? "mConnectedTechIndex" : "mConnectedTechnology", "I"); + e->SetIntField (tag, f, (jint) 0); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers3 +** +** Description: Fill NativeNfcTag's members: mTechPollBytes. +** The original Google's implementation is in set_target_pollBytes( +** in com_android_nfc_NativeNfcTag.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers3"; + jfieldID f = NULL; + jbyteArray pollBytes = e->NewByteArray (0); + jobjectArray techPollBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(pollBytes), 0); + int len = 0; + + for (int i = 0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d; rf tech params mode=%u", fn, i, mTechParams [i].mode); + switch (mTechParams [i].mode) + { + case NFC_DISCOVERY_TYPE_POLL_A: + case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_A: + case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE: + ALOGD ("%s: tech A", fn); + pollBytes = e->NewByteArray (2); + e->SetByteArrayRegion (pollBytes, 0, 2, + (jbyte*) mTechParams [i].param.pa.sens_res); + break; + + case NFC_DISCOVERY_TYPE_POLL_B: + case NFC_DISCOVERY_TYPE_POLL_B_PRIME: + case NFC_DISCOVERY_TYPE_LISTEN_B: + case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME: + if (mTechList [i] == TARGET_TYPE_ISO14443_3B) //is TagTechnology.NFC_B by Java API + { + /***************** + see NFC Forum Digital Protocol specification; section 5.6.2; + in SENSB_RES response, byte 6 through 9 is Application Data, byte 10-12 or 13 is Protocol Info; + used by public API: NfcB.getApplicationData(), NfcB.getProtocolInfo(); + *****************/ + ALOGD ("%s: tech B; TARGET_TYPE_ISO14443_3B", fn); + len = mTechParams [i].param.pb.sensb_res_len; + len = len - 4; //subtract 4 bytes for NFCID0 at byte 2 through 5 + pollBytes = e->NewByteArray (len); + e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) (mTechParams [i].param.pb.sensb_res+4)); + } + else + pollBytes = e->NewByteArray (0); + break; + + case NFC_DISCOVERY_TYPE_POLL_F: + case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_F: + case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE: + { + /**************** + see NFC Forum Type 3 Tag Operation Specification; sections 2.3.2, 2.3.1.2; + see NFC Forum Digital Protocol Specification; sections 6.6.2; + PMm: manufacture parameter; 8 bytes; + System Code: 2 bytes; + ****************/ + ALOGD ("%s: tech F", fn); + UINT8 result [10]; //return result to NFC service + memset (result, 0, sizeof(result)); + len = 10; + + /**** + for (int ii = 0; ii < mTechParams [i].param.pf.sensf_res_len; ii++) + { + ALOGD ("%s: tech F, sendf_res[%d]=%d (0x%x)", + fn, ii, mTechParams [i].param.pf.sensf_res[ii],mTechParams [i].param.pf.sensf_res[ii]); + } + ***/ + memcpy (result, mTechParams [i].param.pf.sensf_res + 8, 8); //copy PMm + if (activationData.params.t3t.num_system_codes > 0) //copy the first System Code + { + UINT16 systemCode = *(activationData.params.t3t.p_system_codes); + result [8] = (UINT8) (systemCode >> 8); + result [9] = (UINT8) systemCode; + ALOGD ("%s: tech F; sys code=0x%X 0x%X", fn, result [8], result [9]); + } + pollBytes = e->NewByteArray (len); + e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) result); + } + break; + + case NFC_DISCOVERY_TYPE_POLL_ISO15693: + case NFC_DISCOVERY_TYPE_LISTEN_ISO15693: + { + ALOGD ("%s: tech iso 15693", fn); + //iso 15693 response flags: 1 octet + //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet + //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags(); + uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid}; + pollBytes = e->NewByteArray (2); + e->SetByteArrayRegion (pollBytes, 0, 2, (jbyte *) data); + } + break; + + default: + ALOGE ("%s: tech unknown ????", fn); + pollBytes = e->NewByteArray(0); + break; + } //switch: every type of technology + e->SetObjectArrayElement (techPollBytes, i, pollBytes); + } //for: every technology in the array + f = e->GetFieldID (tag_cls, "mTechPollBytes", "[[B"); + e->SetObjectField (tag, f, techPollBytes); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers4 +** +** Description: Fill NativeNfcTag's members: mTechActBytes. +** The original Google's implementation is in set_target_activationBytes() +** in com_android_nfc_NativeNfcTag.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers4"; + jfieldID f = NULL; + jbyteArray actBytes = e->NewByteArray (0); + jobjectArray techActBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(actBytes), 0); + jbyteArray uid = NULL; + int len = 0; + + for (int i = 0; i < mNumTechList; i++) + { + ALOGD ("%s: index=%d", fn, i); + switch (mTechLibNfcTypes[i]) + { + case NFC_PROTOCOL_T1T: + { + ALOGD ("%s: T1T; tech A", fn); + actBytes = e->NewByteArray (1); + e->SetByteArrayRegion (actBytes, 0, 1, + (jbyte*) &mTechParams [i].param.pa.sel_rsp); + } + break; + + case NFC_PROTOCOL_T2T: + { + ALOGD ("%s: T2T; tech A", fn); + actBytes = e->NewByteArray (1); + e->SetByteArrayRegion (actBytes, 0, 1, + (jbyte*) &mTechParams [i].param.pa.sel_rsp); + } + break; + + case NFC_PROTOCOL_T3T: //felica + { + ALOGD ("%s: T3T; felica; tech F", fn); + //really, there is no data + actBytes = e->NewByteArray (0); + } + break; + + case NFC_PROTOCOL_ISO_DEP: //t4t + { + if (mTechList [i] == TARGET_TYPE_ISO14443_4) //is TagTechnology.ISO_DEP by Java API + { + if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + //see NFC Forum Digital Protocol specification, section 11.6.2, "RATS Response"; search for "historical bytes"; + //copy historical bytes into Java object; + //the public API, IsoDep.getHistoricalBytes(), returns this data; + if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP) + { + tNFC_INTF_PA_ISO_DEP& pa_iso = activationData.activate_ntf.intf_param.intf_param.pa_iso; + ALOGD ("%s: T4T; ISO_DEP for tech A; copy historical bytes; len=%u", fn, pa_iso.his_byte_len); + actBytes = e->NewByteArray (pa_iso.his_byte_len); + if (pa_iso.his_byte_len > 0) + e->SetByteArrayRegion (actBytes, 0, pa_iso.his_byte_len, (jbyte*) (pa_iso.his_byte)); + } + else + { + ALOGE ("%s: T4T; ISO_DEP for tech A; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type); + actBytes = e->NewByteArray (0); + } + } + else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) ) + { + //see NFC Forum Digital Protocol specification, section 12.6.2, "ATTRIB Response"; + //copy higher-layer response bytes into Java object; + //the public API, IsoDep.getHiLayerResponse(), returns this data; + if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP) + { + tNFC_INTF_PB_ISO_DEP& pb_iso = activationData.activate_ntf.intf_param.intf_param.pb_iso; + ALOGD ("%s: T4T; ISO_DEP for tech B; copy response bytes; len=%u", fn, pb_iso.hi_info_len); + actBytes = e->NewByteArray (pb_iso.hi_info_len); + if (pb_iso.hi_info_len > 0) + e->SetByteArrayRegion (actBytes, 0, pb_iso.hi_info_len, (jbyte*) (pb_iso.hi_info)); + } + else + { + ALOGE ("%s: T4T; ISO_DEP for tech B; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type); + actBytes = e->NewByteArray (0); + } + } + } + else if (mTechList [i] == TARGET_TYPE_ISO14443_3A) //is TagTechnology.NFC_A by Java API + { + ALOGD ("%s: T4T; tech A", fn); + actBytes = e->NewByteArray (1); + e->SetByteArrayRegion (actBytes, 0, 1, (jbyte*) &mTechParams [i].param.pa.sel_rsp); + } + else + { + actBytes = e->NewByteArray (0); + } + } //case NFC_PROTOCOL_ISO_DEP: //t4t + break; + + case NFC_PROTOCOL_15693: + { + ALOGD ("%s: tech iso 15693", fn); + //iso 15693 response flags: 1 octet + //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet + //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags(); + uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid}; + actBytes = e->NewByteArray (2); + e->SetByteArrayRegion (actBytes, 0, 2, (jbyte *) data); + } + break; + + default: + ALOGD ("%s: tech unknown ????", fn); + actBytes = e->NewByteArray (0); + break; + }//switch + e->SetObjectArrayElement (techActBytes, i, actBytes); + } //for: every technology in the array + f = e->GetFieldID (tag_cls, "mTechActBytes", "[[B"); + e->SetObjectField (tag, f, techActBytes); +} + + +/******************************************************************************* +** +** Function: fillNativeNfcTagMembers5 +** +** Description: Fill NativeNfcTag's members: mUid. +** The original Google's implementation is in nfc_jni_Discovery_notification_callback() +** in com_android_nfc_NativeNfcManager.cpp; +** e: JVM environment. +** tag_cls: Java NativeNfcTag class. +** tag: Java NativeNfcTag object. +** activationData: data from activation. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData) +{ + static const char fn [] = "NfcTag::fillNativeNfcTagMembers5"; + jfieldID f = NULL; + int len = 0; + jbyteArray uid = NULL; + + switch (mTechParams [0].mode) + { + case NFC_DISCOVERY_TYPE_POLL_KOVIO: + ALOGD ("%s: Kovio", fn); + len = mTechParams [0].param.pk.uid_len; + uid = e->NewByteArray (len); + e->SetByteArrayRegion (uid, 0, len, + (jbyte*) &mTechParams [0].param.pk.uid); + break; + + case NFC_DISCOVERY_TYPE_POLL_A: + case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_A: + case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE: + ALOGD ("%s: tech A", fn); + len = mTechParams [0].param.pa.nfcid1_len; + uid = e->NewByteArray (len); + e->SetByteArrayRegion (uid, 0, len, + (jbyte*) &mTechParams [0].param.pa.nfcid1); + break; + + case NFC_DISCOVERY_TYPE_POLL_B: + case NFC_DISCOVERY_TYPE_POLL_B_PRIME: + case NFC_DISCOVERY_TYPE_LISTEN_B: + case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME: + ALOGD ("%s: tech B", fn); + uid = e->NewByteArray (NFC_NFCID0_MAX_LEN); + e->SetByteArrayRegion (uid, 0, NFC_NFCID0_MAX_LEN, + (jbyte*) &mTechParams [0].param.pb.nfcid0); + break; + + case NFC_DISCOVERY_TYPE_POLL_F: + case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE: + case NFC_DISCOVERY_TYPE_LISTEN_F: + case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE: + ALOGD ("%s: tech F", fn); + uid = e->NewByteArray (NFC_NFCID2_LEN); + e->SetByteArrayRegion (uid, 0, NFC_NFCID2_LEN, + (jbyte*) &mTechParams [0].param.pf.nfcid2); + break; + + case NFC_DISCOVERY_TYPE_POLL_ISO15693: + case NFC_DISCOVERY_TYPE_LISTEN_ISO15693: + { + ALOGD ("%s: tech iso 15693", fn); + jbyte data [I93_UID_BYTE_LEN]; //8 bytes + for (int i=0; iNewByteArray (I93_UID_BYTE_LEN); + e->SetByteArrayRegion (uid, 0, I93_UID_BYTE_LEN, data); + } + break; + + default: + ALOGE ("%s: tech unknown ????", fn); + uid = e->NewByteArray (0); + break; + } //if + f = e->GetFieldID(tag_cls, "mUid", "[B"); + e->SetObjectField(tag, f, uid); +} + + +/******************************************************************************* +** +** Function: isP2pDiscovered +** +** Description: Does the peer support P2P? +** +** Returns: True if the peer supports P2P. +** +*******************************************************************************/ +bool NfcTag::isP2pDiscovered () +{ + static const char fn [] = "NfcTag::isP2pDiscovered"; + bool retval = false; + + for (int i = 0; i < mNumTechList; i++) + { + if (mTechLibNfcTypes[i] == NFA_PROTOCOL_NFC_DEP) + { + //if remote device supports P2P + ALOGD ("%s: discovered P2P", fn); + retval = true; + break; + } + } + ALOGD ("%s: return=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: selectP2p +** +** Description: Select the preferred P2P technology if there is a choice. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::selectP2p() +{ + static const char fn [] = "NfcTag::selectP2p"; + UINT8 rfDiscoveryId = 0; + + for (int i = 0; i < mNumTechList; i++) + { + //if remote device does not support P2P, just skip it + if (mTechLibNfcTypes[i] != NFA_PROTOCOL_NFC_DEP) + continue; + + //if remote device supports tech F; + //tech F is preferred because it is faster than tech A + if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F_ACTIVE) ) + { + rfDiscoveryId = mTechHandles[i]; + break; //no need to search further + } + else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ) + { + //only choose tech A if tech F is unavailable + if (rfDiscoveryId == 0) + rfDiscoveryId = mTechHandles[i]; + } + } + + if (rfDiscoveryId > 0) + { + ALOGD ("%s: select P2P; target rf discov id=0x%X", fn, rfDiscoveryId); + tNFA_STATUS stat = NFA_Select (rfDiscoveryId, NFA_PROTOCOL_NFC_DEP, NFA_INTERFACE_NFC_DEP); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail select P2P; error=0x%X", fn, stat); + } + else + ALOGE ("%s: cannot find P2P", fn); + resetTechnologies (); +} + + +/******************************************************************************* +** +** Function: resetTechnologies +** +** Description: Clear all data related to the technology, protocol of the tag. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::resetTechnologies () +{ + static const char fn [] = "NfcTag::resetTechnologies"; + ALOGD ("%s", fn); + mNumTechList = 0; + memset (mTechList, 0, sizeof(mTechList)); + memset (mTechHandles, 0, sizeof(mTechHandles)); + memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); + memset (mTechParams, 0, sizeof(mTechParams)); +} + + +/******************************************************************************* +** +** Function: selectFirstTag +** +** Description: When multiple tags are discovered, just select the first one to activate. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::selectFirstTag () +{ + static const char fn [] = "NfcTag::selectFirstTag"; + ALOGD ("%s: nfa target h=0x%X; protocol=0x%X", + fn, mTechHandles [0], mTechLibNfcTypes [0]); + tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME; + + if (mTechLibNfcTypes [0] == NFA_PROTOCOL_ISO_DEP) + { + rf_intf = NFA_INTERFACE_ISO_DEP; + } + else if (mTechLibNfcTypes [0] == NFA_PROTOCOL_NFC_DEP) + rf_intf = NFA_INTERFACE_NFC_DEP; + else + rf_intf = NFA_INTERFACE_FRAME; + + tNFA_STATUS stat = NFA_Select (mTechHandles [0], mTechLibNfcTypes [0], rf_intf); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail select; error=0x%X", fn, stat); +} + + +/******************************************************************************* +** +** Function: getT1tMaxMessageSize +** +** Description: Get the maximum size (octet) that a T1T can store. +** +** Returns: Maximum size in octets. +** +*******************************************************************************/ +int NfcTag::getT1tMaxMessageSize () +{ + static const char fn [] = "NfcTag::getT1tMaxMessageSize"; + + if (mProtocol != NFC_PROTOCOL_T1T) + { + ALOGE ("%s: wrong protocol %u", fn, mProtocol); + return 0; + } + return mtT1tMaxMessageSize; +} + + +/******************************************************************************* +** +** Function: calculateT1tMaxMessageSize +** +** Description: Calculate type-1 tag's max message size based on header ROM bytes. +** activate: reference to activation data. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate) +{ + static const char fn [] = "NfcTag::calculateT1tMaxMessageSize"; + + //make sure the tag is type-1 + if (activate.activate_ntf.protocol != NFC_PROTOCOL_T1T) + { + mtT1tMaxMessageSize = 0; + return; + } + + //examine the first byte of header ROM bytes + switch (activate.params.t1t.hr[0]) + { + case RW_T1T_IS_TOPAZ96: + mtT1tMaxMessageSize = 90; + break; + case RW_T1T_IS_TOPAZ512: + mtT1tMaxMessageSize = 462; + break; + default: + ALOGE ("%s: unknown T1T HR0=%u", fn, activate.params.t1t.hr[0]); + mtT1tMaxMessageSize = 0; + break; + } +} + + +/******************************************************************************* +** +** Function: isMifareUltralight +** +** Description: Whether the currently activated tag is Mifare Ultralight. +** +** Returns: True if tag is Mifare Ultralight. +** +*******************************************************************************/ +bool NfcTag::isMifareUltralight () +{ + static const char fn [] = "NfcTag::isMifareUltralight"; + bool retval = false; + + for (int i =0; i < mNumTechList; i++) + { + if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) || + (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) ) + { + //see NFC Digital Protocol, section 4.6.3 (SENS_RES); section 4.8.2 (SEL_RES). + //see Mifare Type Identification Procedure, section 5.1 (ATQA), 5.2 (SAK). + if ( (mTechParams[i].param.pa.sens_res[0] == 0x44) && + (mTechParams[i].param.pa.sens_res[1] == 0) ) + { + // SyncEventGuard g (mReadCompleteEvent); + // mReadCompletedStatus = NFA_STATUS_BUSY; + // ALOGD ("%s: read block 0x10", fn); + // tNFA_STATUS stat = NFA_RwT2tRead (0x10); + // if (stat == NFA_STATUS_OK) + // mReadCompleteEvent.wait (); + // + // //if read-completion status is failure, then the tag is + // //definitely Mifare Ultralight; + // //if read-completion status is OK, then the tag is + // //definitely Mifare Ultralight C; + // retval = (mReadCompletedStatus == NFA_STATUS_FAILED); + retval = true; + } + break; + } + } + ALOGD ("%s: return=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Handle connection-related events. +** event: event code. +** data: pointer to event data. +** +** Returns: None +** +*******************************************************************************/ +void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) +{ + switch (event) + { + case NFA_DISC_RESULT_EVT: + { + tNFA_DISC_RESULT& disc_result = data->disc_result; + if (disc_result.status == NFA_STATUS_OK) + { + discoverTechnologies (disc_result); + } + } + break; + + case NFA_ACTIVATED_EVT: + // Only do tag detection if we are polling and it is not 'EE Direct RF' activation + // (which may happen when we are activated as a tag). + if (data->activated.activate_ntf.rf_tech_param.mode < NCI_DISCOVERY_TYPE_LISTEN_A + && data->activated.activate_ntf.intf_param.type != NFC_INTERFACE_EE_DIRECT_RF) + { + tNFA_ACTIVATED& activated = data->activated; + if (IsSameKovio(activated)) + break; + mIsActivated = true; + mProtocol = activated.activate_ntf.protocol; + calculateT1tMaxMessageSize (activated); + discoverTechnologies (activated); + createNativeNfcTag (activated); + } + break; + + case NFA_DEACTIVATED_EVT: + mIsActivated = false; + mProtocol = NFC_PROTOCOL_UNKNOWN; + resetTechnologies (); + break; + + case NFA_READ_CPLT_EVT: + { + SyncEventGuard g (mReadCompleteEvent); + mReadCompletedStatus = data->status; + mReadCompleteEvent.notifyOne (); + } + break; + } +} + diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h new file mode 100755 index 0000000..2b17553 --- /dev/null +++ b/nci/jni/NfcTag.h @@ -0,0 +1,357 @@ +/***************************************************************************** +** +** Name: NfcTag.h +** +** Description: Tag-reading, tag-writing operations. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#pragma once +#include "SyncEvent.h" +#include "NfcJniUtil.h" +extern "C" +{ + #include "nfa_rw_api.h" +} + + +class NfcTag +{ +public: + static const int MAX_NUM_TECHNOLOGY = 10; //max number of technologies supported by one or more tags + int mTechList [MAX_NUM_TECHNOLOGY]; //array of NFC technologies according to NFC service + int mTechHandles [MAX_NUM_TECHNOLOGY]; //array of tag handles according to NFC service + int mTechLibNfcTypes [MAX_NUM_TECHNOLOGY]; //array of detailed tag types according to NFC service + int mNumTechList; //current number of NFC technologies in the list + + /******************************************************************************* + ** + ** Function: NfcTag + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + NfcTag (); + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get a reference to the singleton NfcTag object. + ** + ** Returns: Reference to NfcTag object. + ** + *******************************************************************************/ + static NfcTag& getInstance (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Reset member variables. + ** native: Native data. + ** Returns: None + ** + *******************************************************************************/ + void initialize (nfc_jni_native_data* native); + + + /******************************************************************************* + ** + ** Function: abort + ** + ** Description: Unblock all operations. + ** + ** Returns: None + ** + *******************************************************************************/ + void abort (); + + + /******************************************************************************* + ** + ** Function: connectionEventHandler + ** + ** Description: Handle connection-related events. + ** event: event code. + ** data: pointer to event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data); + + + /******************************************************************************* + ** + ** Function: isActivated + ** + ** Description: Is tag activated? + ** + ** Returns: True if tag is activated. + ** + *******************************************************************************/ + bool isActivated (); + + + /******************************************************************************* + ** + ** Function: getProtocol + ** + ** Description: Get the protocol of the current tag. + ** + ** Returns: Protocol number. + ** + *******************************************************************************/ + tNFC_PROTOCOL getProtocol (); + + + /******************************************************************************* + ** + ** Function: isP2pDiscovered + ** + ** Description: Does the peer support P2P? + ** + ** Returns: True if the peer supports P2P. + ** + *******************************************************************************/ + bool isP2pDiscovered (); + + + /******************************************************************************* + ** + ** Function: selectP2p + ** + ** Description: Select the preferred P2P technology if there is a choice. + ** + ** Returns: None + ** + *******************************************************************************/ + void selectP2p (); + + + /******************************************************************************* + ** + ** Function: selectFirstTag + ** + ** Description: When multiple tags are discovered, just select the first one to activate. + ** + ** Returns: None + ** + *******************************************************************************/ + void selectFirstTag (); + + + /******************************************************************************* + ** + ** Function: getT1tMaxMessageSize + ** + ** Description: Get the maximum size (octet) that a T1T can store. + ** + ** Returns: Maximum size in octets. + ** + *******************************************************************************/ + int getT1tMaxMessageSize (); + + + /******************************************************************************* + ** + ** Function: isMifareUltralight + ** + ** Description: Whether the currently activated tag is Mifare Ultralight. + ** + ** Returns: True if tag is Mifare Ultralight. + ** + *******************************************************************************/ + bool isMifareUltralight (); + +private: + nfc_jni_native_data* mNativeData; + bool mIsActivated; + tNFC_PROTOCOL mProtocol; + int mtT1tMaxMessageSize; //T1T max NDEF message size + tNFA_STATUS mReadCompletedStatus; + tNFC_RF_TECH_PARAMS mTechParams [MAX_NUM_TECHNOLOGY]; //array of technology parameters + SyncEvent mReadCompleteEvent; + int mLastKovioUidLen; // len of uid of last Kovio tag activated + struct timespec mLastKovioTime; // time of last Kovio tag activation + UINT8 mLastKovioUid[NFC_KOVIO_MAX_LEN]; // uid of last Kovio tag activated + + + /******************************************************************************* + ** + ** Function: IsSameKovio + ** + ** Description: Checks if tag activate is the same (UID) Kovio tag previously + ** activated. This is needed due to a problem with some Kovio + ** tags re-activating multiple times. + ** activationData: data from activation. + ** + ** Returns: true if the activation is from the same tag previously + ** activated, false otherwise + ** + *******************************************************************************/ + bool IsSameKovio(tNFA_ACTIVATED& activationData); + + /******************************************************************************* + ** + ** Function: discoverTechnologies + ** + ** Description: Discover the technologies that NFC service needs by interpreting + ** the data strucutures from the stack. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void discoverTechnologies (tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: discoverTechnologies + ** + ** Description: Discover the technologies that NFC service needs by interpreting + ** the data strucutures from the stack. + ** discoveryData: data from discovery events(s). + ** + ** Returns: None + ** + *******************************************************************************/ + void discoverTechnologies (tNFA_DISC_RESULT& discoveryData); + + + /******************************************************************************* + ** + ** Function: createNativeNfcTag + ** + ** Description: Create a brand new Java NativeNfcTag object; + ** fill the objects's member variables with data; + ** notify NFC service; + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void createNativeNfcTag (tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers1 + ** + ** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes. + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers2 + ** + ** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology. + ** The original Google's implementation is in set_target_pollBytes( + ** in com_android_nfc_NativeNfcTag.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers3 + ** + ** Description: Fill NativeNfcTag's members: mTechPollBytes. + ** The original Google's implementation is in set_target_pollBytes( + ** in com_android_nfc_NativeNfcTag.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers4 + ** + ** Description: Fill NativeNfcTag's members: mTechActBytes. + ** The original Google's implementation is in set_target_activationBytes() + ** in com_android_nfc_NativeNfcTag.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: fillNativeNfcTagMembers5 + ** + ** Description: Fill NativeNfcTag's members: mUid. + ** The original Google's implementation is in nfc_jni_Discovery_notification_callback() + ** in com_android_nfc_NativeNfcManager.cpp; + ** e: JVM environment. + ** tag_cls: Java NativeNfcTag class. + ** tag: Java NativeNfcTag object. + ** activationData: data from activation. + ** + ** Returns: None + ** + *******************************************************************************/ + void fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData); + + + /******************************************************************************* + ** + ** Function: resetTechnologies + ** + ** Description: Clear all data related to the technology, protocol of the tag. + ** + ** Returns: None + ** + *******************************************************************************/ + void resetTechnologies (); + + + /******************************************************************************* + ** + ** Function: calculateT1tMaxMessageSize + ** + ** Description: Calculate type-1 tag's max message size based on header ROM bytes. + ** activate: reference to activation data. + ** + ** Returns: None + ** + *******************************************************************************/ + void calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate); +}; + diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp new file mode 100644 index 0000000..4c02da2 --- /dev/null +++ b/nci/jni/PeerToPeer.cpp @@ -0,0 +1,2158 @@ +/***************************************************************************** +** +** Name: PeerToPeer.cpp +** +** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include "PeerToPeer.h" +#include "NfcJniUtil.h" +#include "llcp_defs.h" +#include "config.h" + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; + extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; + extern void nativeNfcTag_registerNdefTypeHandler (); + extern void nativeNfcTag_deregisterNdefTypeHandler (); +} + + +PeerToPeer PeerToPeer::sP2p; +const std::string PeerToPeer::sSnepServiceName ("urn:nfc:sn:snep"); +const std::string PeerToPeer::sNppServiceName ("com.android.npp"); + + +/******************************************************************************* +** +** Function: PeerToPeer +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +PeerToPeer::PeerToPeer () +: mRemoteWKS (0), + mIsP2pListening (false), + mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A + | NFA_TECHNOLOGY_MASK_F + | NFA_TECHNOLOGY_MASK_A_ACTIVE + | NFA_TECHNOLOGY_MASK_F_ACTIVE), + mJniHandleSendingNppViaSnep (0), + mSnepRegHandle (NFA_HANDLE_INVALID), + mRcvFakeNppJniHandle (0), + mNppFakeOutBuffer (NULL), + mNppTotalLen (0), + mNppReadSoFar (0), + mNdefTypeHandlerHandle (NFA_HANDLE_INVALID), + mAppLogLevel (1), + mJniVersion (403) +{ + unsigned long num = 0; + memset (mServers, 0, sizeof(mServers)); + memset (mClients, 0, sizeof(mClients)); + if (GetNumValue ("APPL_TRACE_LEVEL", &num, sizeof (num))) + mAppLogLevel = num; + + if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) + mP2pListenTechMask = num; +} + + +/******************************************************************************* +** +** Function: ~PeerToPeer +** +** Description: Free all resources. +** +** Returns: None +** +*******************************************************************************/ +PeerToPeer::~PeerToPeer () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the singleton PeerToPeer object. +** +** Returns: Singleton PeerToPeer object. +** +*******************************************************************************/ +PeerToPeer& PeerToPeer::getInstance () +{ + return sP2p; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize member variables. +** jniVersion: JNI version. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::initialize (long jniVersion) +{ + ALOGD ("PeerToPeer::initialize"); + mJniVersion = jniVersion; +} + + +/******************************************************************************* +** +** Function: findServer +** +** Description: Find a PeerToPeer object by connection handle. +** nfaP2pServerHandle: Connectin handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pServer *PeerToPeer::findServer (tNFA_HANDLE nfaP2pServerHandle) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) + && (mServers[i]->mNfaP2pServerHandle == nfaP2pServerHandle) ) + { + return (mServers [i]); + } + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: findServer +** +** Description: Find a PeerToPeer object by connection handle. +** serviceName: service name. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pServer *PeerToPeer::findServer (tBRCM_JNI_HANDLE jniHandle) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) + && (mServers[i]->mJniHandle == jniHandle) ) + { + return (mServers [i]); + } + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: findServer +** +** Description: Find a PeerToPeer object by service name +** serviceName: service name. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pServer *PeerToPeer::findServer (const char *serviceName) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) && (mServers[i]->mServiceName.compare(serviceName) == 0) ) + return (mServers [i]); + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: registerServer +** +** Description: Let a server start listening for peer's connection request. +** jniHandle: Connection handle. +** serviceName: Server's service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *serviceName) +{ + static const char fn [] = "PeerToPeer::registerServer"; + ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle); + tNFA_STATUS stat = NFA_STATUS_OK; + P2pServer *pSrv = NULL; + UINT8 serverSap = NFA_P2P_ANY_SAP; + + // Check if already registered + if ((pSrv = findServer(serviceName)) != NULL) + { + ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle); + + // Update JNI handle + pSrv->mJniHandle = jniHandle; + return (true); + } + + for (int ii = 0; ii < sMax; ii++) + { + if (mServers[ii] == NULL) + { + pSrv = mServers[ii] = new P2pServer; + pSrv->mServiceName.assign (serviceName); + pSrv->mJniHandle = jniHandle; + + ALOGD ("%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName); + break; + } + } + + if (pSrv == NULL) + { + ALOGE ("%s: service name=%s no free entry", fn, serviceName); + return (false); + } + + /********************** + default values for all LLCP parameters: + - Local Link MIU (LLCP_MIU) + - Option parameter (LLCP_OPT_VALUE) + - Response Waiting Time Index (LLCP_WAITING_TIME) + - Local Link Timeout (LLCP_LTO_VALUE) + - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT) + - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT) + - Delay SYMM response (LLCP_DELAY_RESP_TIME) + - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) + - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) + ************************/ + stat = NFA_P2pSetLLCPConfig (LLCP_MIU, + LLCP_OPT_VALUE, + LLCP_WAITING_TIME, + LLCP_LTO_VALUE, + 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator + 0, //use 0 for infinite timeout for symmetry procedure when acting as target + LLCP_DELAY_RESP_TIME, + LLCP_DATA_LINK_CONNECTION_TOUT, + LLCP_DELAY_TIME_TO_SEND_FIRST_PDU); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat); + + if (sSnepServiceName.compare(serviceName) == 0) + serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 + + SyncEventGuard guard (pSrv->mListenEvent); + stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); + if (stat != NFA_STATUS_OK) + { + ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); + removeServer (jniHandle); + return (false); + } + ALOGD ("%s: wait for listen-completion event", fn); + // Wait for NFA_P2P_LISTEN_EVT + pSrv->mListenEvent.wait (); + + if (pSrv->mNfaP2pServerHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid server handle", fn); + removeServer (jniHandle); + return (false); + } + else + { + ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle); + return (true); + } +} + + +/******************************************************************************* +** +** Function: removeServer +** +** Description: Free resources related to a server. +** jniHandle: Connection handle. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::removeServer (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::removeServer"; + + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) && (mServers[i]->mJniHandle == jniHandle) ) + { + ALOGD ("%s: server jni_handle: %u; nfa_handle: 0x%04x; name: %s; index=%d", + fn, jniHandle, mServers[i]->mNfaP2pServerHandle, mServers[i]->mServiceName.c_str(), i); + + delete mServers [i]; + mServers [i] = NULL; + return; + } + } + ALOGE ("%s: unknown server jni handle: %u", fn, jniHandle); +} + + +/******************************************************************************* +** +** Function: llcpActivatedHandler +** +** Description: Receive LLLCP-activated event from stack. +** nat: JVM-related data. +** activated: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIVATED& activated) +{ + static const char fn [] = "PeerToPeer::llcpActivatedHandler"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + jclass tag_cls = NULL; + jobject tag = NULL; + jmethodID ctor = 0; + jfieldID f = 0; + + //no longer need to receive NDEF message from a tag + android::nativeNfcTag_deregisterNdefTypeHandler (); + + //register a type handler in case we need to send NDEF messages received from SNEP through NPP + mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; + NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *)"", 0, ndefTypeCallback); + + mRemoteWKS = activated.remote_wks; + + nat->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + ALOGD ("%s: get object class", fn); + tag_cls = e->GetObjectClass (nat->cached_P2pDevice); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail get p2p device", fn); + goto TheEnd; + } + + ALOGD ("%s: instantiate", fn); + /* New target instance */ + ctor = e->GetMethodID (tag_cls, "", "()V"); + tag = e->NewObject (tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID (tag_cls, "mMode", "I"); + + if (activated.is_initiator == TRUE) + { + ALOGD ("%s: p2p initiator", fn); + e->SetIntField (tag, f, (jint) MODE_P2P_INITIATOR); + } + else + { + ALOGD ("%s: p2p target", fn); + e->SetIntField (tag, f, (jint) MODE_P2P_TARGET); + } + + /* Set tag handle */ + f = e->GetFieldID (tag_cls, "mHandle", "I"); + e->SetIntField (tag, f, (jint) 0x1234); // ?? This handle is not used for anything + + if (nat->tag != NULL) + { + e->DeleteGlobalRef (nat->tag); + } + nat->tag = e->NewGlobalRef (tag); + + ALOGD ("%s: notify nfc service", fn); + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkActivation, tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + e->DeleteLocalRef (tag); + +TheEnd: + nat->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: llcpDeactivatedHandler +** +** Description: Receive LLLCP-deactivated event from stack. +** nat: JVM-related data. +** deactivated: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEACTIVATED& deactivated) +{ + static const char fn [] = "PeerToPeer::llcpDeactivatedHandler"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + + nat->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + ALOGD ("%s: notify nfc service", fn); + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkDeactivated, nat->tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + nat->vm->DetachCurrentThread (); + + //PeerToPeer no longer needs to handle NDEF data event + NFA_DeregisterNDefTypeHandler (mNdefTypeHandlerHandle); + mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; + + //let the tag-reading code handle NDEF data event + android::nativeNfcTag_registerNdefTypeHandler (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: accept +** +** Description: Accept a peer's request to connect. +** serverJniHandle: Server's handle. +** connJniHandle: Connection handle. +** maxInfoUnit: Maximum information unit. +** recvWindow: Receive window size. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow) +{ + static const char fn [] = "PeerToPeer::accept"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + NfaConn *pConn = NULL; + bool stat = false; + int ii = 0; + P2pServer *pSrv = NULL; + + ALOGD ("%s: enter; server jni handle: %u; conn jni handle: %u; maxInfoUnit: %d; recvWindow: %d", fn, + serverJniHandle, connJniHandle, maxInfoUnit, recvWindow); + + if ((pSrv = findServer (serverJniHandle)) == NULL) + { + ALOGE ("%s: unknown server jni handle: %u", fn, serverJniHandle); + return (false); + } + + // First, find a free connection block to handle the connection + for (ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++) + { + if (pSrv->mServerConn[ii] == NULL) + { + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; allocate server conn index: %u", fn, + serverJniHandle, connJniHandle, ii); + pSrv->mServerConn[ii] = new NfaConn; + pSrv->mServerConn[ii]->mJniHandle = connJniHandle; + break; + } + } + + if (ii == MAX_NFA_CONNS_PER_SERVER) + { + ALOGE ("%s: fail allocate connection block", fn); + return (false); + } + + { + // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection + SyncEventGuard guard (pSrv->mConnRequestEvent); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; wait for incoming connection", fn, + serverJniHandle, connJniHandle, ii); + pSrv->mConnRequestEvent.wait(); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X; got incoming connection", fn, + serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); + } + + // If we had gotten a message via SNEP, fake it out to be for NPP + if (mRcvFakeNppJniHandle == serverJniHandle) + { + ALOGD ("%s: server jni handle %u diverted to NPP fake receive on conn jni handle %u", fn, serverJniHandle, connJniHandle); + delete (pSrv->mServerConn[ii]); + pSrv->mServerConn[ii] = NULL; + mRcvFakeNppJniHandle = connJniHandle; + return (true); + } + + if (pSrv->mServerConn[ii]->mNfaConnHandle == NFA_HANDLE_INVALID) + { + delete (pSrv->mServerConn[ii]); + pSrv->mServerConn[ii] = NULL; + ALOGD ("%s: no handle assigned", fn); + return (false); + } + + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X; try accept", fn, + serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); + nfaStat = NFA_P2pAcceptConn (pSrv->mServerConn[ii]->mNfaConnHandle, maxInfoUnit, recvWindow); + + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat); + return (false); + } + + ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X", fn, + serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); + return (true); +} + + +/******************************************************************************* +** +** Function: deregisterServer +** +** Description: Stop a P2pServer from listening for peer. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::deregisterServer"; + ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pServer *pSrv = NULL; + + if ((pSrv = findServer (jniHandle)) == NULL) + { + ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service handle: %u", fn, jniHandle); + return (false); + } + + // Server does not call NFA_P2pDisconnect(), so unblock the accept() + SyncEventGuard guard (pSrv->mConnRequestEvent); + pSrv->mConnRequestEvent.notifyOne(); + + nfaStat = NFA_P2pDeregister (pSrv->mNfaP2pServerHandle); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: deregister error=0x%X", fn, nfaStat); + } + + removeServer (jniHandle); + + ALOGD ("%s: exit", fn); + return true; +} + + +/******************************************************************************* +** +** Function: createClient +** +** Description: Create a P2pClient object for a new out-bound connection. +** jniHandle: Connection handle. +** miu: Maximum information unit. +** rw: Receive window size. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) +{ + static const char fn [] = "PeerToPeer::createClient"; + int i = 0; + ALOGD ("%s: enter: jni h: %u miu: %u rw: %u", fn, jniHandle, miu, rw); + + for (i = 0; i < sMax; i++) + { + if (mClients[i] == NULL) + { + mClients [i] = new P2pClient; + + mClients [i]->mClientConn.mJniHandle = jniHandle; + mClients [i]->mClientConn.mMaxInfoUnit = miu; + mClients [i]->mClientConn.mRecvWindow = rw; + break; + } + } + + if (i == sMax) + { + ALOGE ("%s: fail", fn); + return (false); + } + + ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, mClients[i], jniHandle); + + SyncEventGuard guard (mClients[i]->mRegisteringEvent); + NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback); + mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT + + if (mClients[i]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, mClients[i]->mClientConn.mNfaConnHandle); + return (true); + } + else + { + ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, mClients[i]->mClientConn.mNfaConnHandle); + removeConn (jniHandle); + return (false); + } +} + + +/******************************************************************************* +** +** Function: removeConn +** +** Description: Free resources related to a connection. +** jniHandle: Connection handle. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::removeConn(tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn[] = "PeerToPeer::removeConn"; + int ii = 0, jj = 0; + + // If the connection is a for a client, delete the client itself + for (ii = 0; ii < sMax; ii++) + { + if (mClients[ii] && (mClients[ii]->mClientConn.mJniHandle == jniHandle)) + { + if (mClients[ii]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) + NFA_P2pDeregister (mClients[ii]->mNfaP2pClientHandle); + + delete mClients[ii]; + mClients[ii] = NULL; + ALOGD ("%s: deleted client handle: %u index: %u", fn, jniHandle, ii); + return; + } + } + + // If the connection is for a server, just delete the connection + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServers[ii]->mServerConn[jj] != NULL) + && (mServers[ii]->mServerConn[jj]->mJniHandle == jniHandle) ) + { + ALOGD ("%s: delete server conn jni h: %u; index: %d; server jni h: %u", + fn, mServers[ii]->mServerConn[jj]->mJniHandle, jj, mServers[ii]->mJniHandle); + delete mServers[ii]->mServerConn[jj]; + mServers[ii]->mServerConn[jj] = NULL; + return; + } + } + } + } + + if (jniHandle == mRcvFakeNppJniHandle) + { + ALOGD ("%s: Reset mRcvFakeNppJniHandle: %u", fn, jniHandle); + mRcvFakeNppJniHandle = 0; + if (mNppFakeOutBuffer != NULL) + { + free (mNppFakeOutBuffer); + mNppFakeOutBuffer = NULL; + } + } + else + ALOGE ("%s: could not find handle: %u", fn, jniHandle); +} + + +/******************************************************************************* +** +** Function: connectConnOriented +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** serviceName: Peer's service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName) +{ + static const char fn [] = "PeerToPeer::connectConnOriented"; + ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName); + + // If we are connecting to NPP and the other side supports SNEP, use SNEP + if ( (sNppServiceName.compare(serviceName)==0) && (mSnepRegHandle != NFA_HANDLE_INVALID) ) + { + P2pClient *pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + return (false); + } + + if (mJniHandleSendingNppViaSnep != 0) + { + ALOGE ("%s: SNEP already active, SNEP JNI handle: %u new JNI handle: %u", fn, mJniHandleSendingNppViaSnep, jniHandle); + return (false); + } + + // Save JNI Handle and try to connect to SNEP + mJniHandleSendingNppViaSnep = jniHandle; + + if (NFA_SnepConnect (mSnepRegHandle, "urn:nfc:sn:snep") == NFA_STATUS_OK) + { + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.wait(); + + // If the connect attempt failed, connection handle is invalid + if (pClient->mSnepConnHandle != NFA_HANDLE_INVALID) + { + // return true, as if we were connected. + pClient->mClientConn.mRemoteMaxInfoUnit = 248; + pClient->mClientConn.mRemoteRecvWindow = 1; + return (true); + } + } + mJniHandleSendingNppViaSnep = 0; + } + + // If here, we did not establish a SNEP connection + bool stat = createDataLinkConn (jniHandle, serviceName, 0); + ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); + return stat; +} + + +/******************************************************************************* +** +** Function: connectConnOriented +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** destinationSap: Peer's service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap) +{ + static const char fn [] = "PeerToPeer::connectConnOriented"; + ALOGD ("%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap); + bool stat = createDataLinkConn (jniHandle, NULL, destinationSap); + ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); + return stat; +} + + +/******************************************************************************* +** +** Function: createDataLinkConn +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** serviceName: Peer's service name. +** destinationSap: Peer's service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap) +{ + static const char fn [] = "PeerToPeer::createDataLinkConn"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pClient *pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + return (false); + } + + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mIsConnecting = true; + + if (serviceName) + nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle, + const_cast(serviceName), pClient->mClientConn.mMaxInfoUnit, + pClient->mClientConn.mRecvWindow); + else if (destinationSap) + nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap, + pClient->mClientConn.mMaxInfoUnit, pClient->mClientConn.mRecvWindow); + + if (nfaStat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient); + pClient->mConnectingEvent.wait(); + + if (pClient->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) + { + removeConn (jniHandle); + nfaStat = NFA_STATUS_FAILED; + } + else + pClient->mIsConnecting = false; + } + else + { + removeConn (jniHandle); + ALOGE ("%s: fail; error=0x%X", fn, nfaStat); + } + + ALOGD ("%s: exit", fn); + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: findClient +** +** Description: Find a PeerToPeer object with a client connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pClient *PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) +{ + for (int i = 0; i < sMax; i++) + { + if (mClients[i] && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findClient +** +** Description: Find a PeerToPeer object with a client connection handle. +** jniHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pClient *PeerToPeer::findClient (tBRCM_JNI_HANDLE jniHandle) +{ + for (int i = 0; i < sMax; i++) + { + if (mClients[i] && (mClients[i]->mClientConn.mJniHandle == jniHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findClientCon +** +** Description: Find a PeerToPeer object with a client connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +P2pClient *PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) +{ + for (int i = 0; i < sMax; i++) + { + if (mClients[i] && (mClients[i]->mClientConn.mNfaConnHandle == nfaConnHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findConnection +** +** Description: Find a PeerToPeer object with a connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) +{ + int ii = 0, jj = 0; + + // First, look through all the client control blocks + for (ii = 0; ii < sMax; ii++) + { + if ( (mClients[ii] != NULL) + && (mClients[ii]->mClientConn.mNfaConnHandle == nfaConnHandle) ) + return (&mClients[ii]->mClientConn); + } + + // Not found yet. Look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServers[ii]->mServerConn[jj] != NULL) + && (mServers[ii]->mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) + return (mServers[ii]->mServerConn[jj]); + } + } + } + + // Not found... + return NULL; +} + + +/******************************************************************************* +** +** Function: findConnection +** +** Description: Find a PeerToPeer object with a connection handle. +** jniHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +NfaConn *PeerToPeer::findConnection (tBRCM_JNI_HANDLE jniHandle) +{ + int ii = 0, jj = 0; + + // First, look through all the client control blocks + for (ii = 0; ii < sMax; ii++) + { + if ( (mClients[ii] != NULL) + && (mClients[ii]->mClientConn.mJniHandle == jniHandle) ) + return (&mClients[ii]->mClientConn); + } + + // Not found yet. Look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServers[ii]->mServerConn[jj] != NULL) + && (mServers[ii]->mServerConn[jj]->mJniHandle == jniHandle) ) + return (mServers[ii]->mServerConn[jj]); + } + } + } + + // Not found... + return NULL; +} + + +/******************************************************************************* +** +** Function: send +** +** Description: Send data to peer. +** jniHandle: Handle of connection. +** buffer: Buffer of data. +** bufferLen: Length of data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) +{ + static const char fn [] = "PeerToPeer::send"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + NfaConn *pConn = NULL; + + if ((pConn = findConnection (jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X mJniHandleSendingNppViaSnep: %u", + fn, pConn->mJniHandle, pConn->mNfaConnHandle, mJniHandleSendingNppViaSnep); + + // Is this a SNEP fake-out + if (jniHandle == mJniHandleSendingNppViaSnep) + { + return (sendViaSnep(jniHandle, buffer, bufferLen)); + } + + nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + + while (nfaStat == NFA_STATUS_CONGESTED) + { + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.wait (); + + if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + return (false); + + nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + } + + if (nfaStat == NFA_STATUS_OK) + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle); + else + ALOGE ("%s: Data not sent; JNI handle: %u NFA Handle: 0x%04x error: 0x%04x", + fn, jniHandle, pConn->mNfaConnHandle, nfaStat); + + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: sendViaSnep +** +** Description: Send out-bound data to the stack's SNEP protocol. +** jniHandle: Handle of connection. +** buffer: Buffer of data. +** dataLen: Length of data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 dataLen) +{ + static const char fn [] = "PeerToPeer::sendViaSnep"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pClient *pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + mJniHandleSendingNppViaSnep = 0; + return (false); + } + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u mSnepNdefMsgLen: %lu mSnepNdefBufLen: %lu dataLen: %d", + fn, jniHandle, pClient->mSnepNdefMsgLen, pClient->mSnepNdefBufLen, dataLen); + + if (pClient->mSnepNdefMsgLen == 0) + { + pClient->mSnepNdefMsgLen = (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | buffer[9]; + if ((pClient->mSnepNdefBuf = (UINT8 *)malloc (pClient->mSnepNdefMsgLen + 1000)) == NULL) + { + ALOGE ("%s: can't malloc len: %lu", fn, pClient->mSnepNdefMsgLen); + mJniHandleSendingNppViaSnep = 0; + return (false); + } + buffer += 10; + dataLen -= 10; + } + + if ((pClient->mSnepNdefBufLen + dataLen) > pClient->mSnepNdefMsgLen) + { + ALOGE ("%s: len error mSnepNdefBufLen: %lu dataLen: %u mSnepNdefMsgLen: %lu", fn, + pClient->mSnepNdefBufLen, dataLen, pClient->mSnepNdefMsgLen); + mJniHandleSendingNppViaSnep = 0; + free (pClient->mSnepNdefBuf); + pClient->mSnepNdefBuf = NULL; + return (false); + } + + // Save the data in the buffer + memcpy (pClient->mSnepNdefBuf + pClient->mSnepNdefBufLen, buffer, dataLen); + + pClient->mSnepNdefBufLen += dataLen; + + // If we got all the data, send it via SNEP + if (pClient->mSnepNdefBufLen == pClient->mSnepNdefMsgLen) + { + ALOGD ("%s GKI_poolcount(2): %u GKI_poolfreecount(2): %u", fn, GKI_poolcount(2), GKI_poolfreecount(2)); + + nfaStat = NFA_SnepPut (pClient->mSnepConnHandle, pClient->mSnepNdefBufLen, pClient->mSnepNdefBuf); + + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_SnepPut failed, code: 0x%04x", fn, nfaStat); + mJniHandleSendingNppViaSnep = 0; + free (pClient->mSnepNdefBuf); + pClient->mSnepNdefBuf = NULL; + return (false); + } + + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.wait (); + + free (pClient->mSnepNdefBuf); + pClient->mSnepNdefBuf = NULL; + mJniHandleSendingNppViaSnep = 0; + return (pClient->mIsSnepSentOk); + } + return (true); +} + + +/******************************************************************************* +** +** Function: receive +** +** Description: Receive data from peer. +** jniHandle: Handle of connection. +** buffer: Buffer to store data. +** bufferLen: Max length of buffer. +** actualLen: Actual length received. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) +{ + static const char fn [] = "PeerToPeer::receive"; + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); + NfaConn *pConn = NULL; + + if (jniHandle == mRcvFakeNppJniHandle) + return (feedNppFromSnep(buffer, bufferLen, actualLen)); + + if ((pConn = findConnection (jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); + + // Only wait for data if data queue is empty. + if (pConn->mInboundQ.isEmpty()) + { + // And don't wait if we're disconnected. + if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + { + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.wait(); + } + + // If the connection was disconnected while we were blocked... + if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + { + ALOGD ("%s: already disconnected while waiting", fn); + return (false); + } + } + + bool stat = pConn->mInboundQ.dequeue (buffer, bufferLen, actualLen); + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; client h=0x%X stat=%u actual len=%u", fn, pConn->mNfaConnHandle, stat, actualLen); + return stat; +} + + +/******************************************************************************* +** +** Function: feedNppFromSnep +** +** Description: Send incomming data to the NFC service's NDEF Push Protocol. +** buffer: Buffer of data to send. +** bufferLen: Length of data in buffer. +** actualLen: Actual length sent. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) +{ + static const char fn [] = "PeerToPeer::feedNppFromSnep"; + + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: mNppTotalLen: %lu mNppReadSoFar: %lu bufferLen: %u", + fn, mNppTotalLen, mNppReadSoFar, bufferLen); + + if (bufferLen > (mNppTotalLen - mNppReadSoFar)) + bufferLen = mNppTotalLen - mNppReadSoFar; + + memcpy (buffer, mNppFakeOutBuffer + mNppReadSoFar, bufferLen); + + mNppReadSoFar += bufferLen; + actualLen = bufferLen; + + if (mNppReadSoFar == mNppTotalLen) + { + ALOGD ("%s: entire message consumed", fn); + free (mNppFakeOutBuffer); + mNppFakeOutBuffer = NULL; + mRcvFakeNppJniHandle = 0; + } + return (true); +} + + +/******************************************************************************* +** +** Function: disconnectConnOriented +** +** Description: Disconnect a connection-oriented connection with peer. +** jniHandle: Handle of connection. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::disconnectConnOriented"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + P2pClient *pClient = NULL; + NfaConn *pConn = NULL; + + ALOGD ("%s: enter; jni handle: %u", fn, jniHandle); + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + // If this is a client, he may not be connected yet, so unblock him just in case + if ( ((pClient = findClient(jniHandle)) != NULL) && (pClient->mIsConnecting) ) + { + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mConnectingEvent.notifyOne(); + return (true); + } + + { + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne (); //unblock send() if congested + } + { + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne (); //unblock receive() + } + + if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: try disconn nfa h=0x%04X", fn, pConn->mNfaConnHandle); + SyncEventGuard guard (pConn->mDisconnectingEvent); + nfaStat = NFA_P2pDisconnect (pConn->mNfaConnHandle, FALSE); + + if (nfaStat != NFA_STATUS_OK) + ALOGE ("%s: fail p2p disconnect", fn); + else + pConn->mDisconnectingEvent.wait(); + } + + mDisconnectMutex.lock (); + removeConn (jniHandle); + mDisconnectMutex.unlock (); + + ALOGD ("%s: exit; jni handle: %u", fn, jniHandle); + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: getRemoteMaxInfoUnit +** +** Description: Get peer's max information unit. +** jniHandle: Handle of the connection. +** +** Returns: Peer's max information unit. +** +*******************************************************************************/ +UINT16 PeerToPeer::getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit"; + NfaConn *pConn = NULL; + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find client jniHandle: %u", fn, jniHandle); + return 0; + } + ALOGD ("%s: jniHandle: %u MIU: %u", fn, jniHandle, pConn->mRemoteMaxInfoUnit); + return (pConn->mRemoteMaxInfoUnit); +} + + +/******************************************************************************* +** +** Function: getRemoteRecvWindow +** +** Description: Get peer's receive window size. +** jniHandle: Handle of the connection. +** +** Returns: Peer's receive window size. +** +*******************************************************************************/ +UINT8 PeerToPeer::getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::getRemoteRecvWindow"; + ALOGD ("%s: client jni handle: %u", fn, jniHandle); + NfaConn *pConn = NULL; + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find client", fn); + return 0; + } + return pConn->mRemoteRecvWindow; +} + + +/******************************************************************************* +** +** Function: enableP2pListening +** +** Description: Start/stop polling/listening to peer that supports P2P. +** isEnable: Is enable polling/listening? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::enableP2pListening (bool isEnable) +{ + static const char fn [] = "PeerToPeer::enableP2pListening"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + + ALOGD ("%s: enter isEnable: %u mIsP2pListening: %u", fn, isEnable, mIsP2pListening); + + // If request to enable P2P listening, and we were not already listening + if ( (isEnable == true) && (mIsP2pListening == false) && (mP2pListenTechMask != 0) ) + { + SyncEventGuard guard (mSetTechEvent); + if ((nfaStat = NFA_SetP2pListenTech (mP2pListenTechMask)) == NFA_STATUS_OK) + { + mSetTechEvent.wait (); + mIsP2pListening = true; + } + else + ALOGE ("%s: fail enable listen; error=0x%X", fn, nfaStat); + } + else if ( (isEnable == false) && (mIsP2pListening == true) ) + { + SyncEventGuard guard (mSetTechEvent); + // Request to disable P2P listening, check if it was enabled + if ((nfaStat = NFA_SetP2pListenTech(0)) == NFA_STATUS_OK) + { + mSetTechEvent.wait (); + mIsP2pListening = false; + } + else + ALOGE ("%s: fail disable listen; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit; mIsP2pListening: %u", fn, mIsP2pListening); +} + + +/******************************************************************************* +** +** Function: handleNfcOnOff +** +** Description: Handle events related to turning NFC on/off by the user. +** isOn: Is NFC turning on? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::handleNfcOnOff (bool isOn) +{ + static const char fn [] = "PeerToPeer::handleNfcOnOff"; + ALOGD ("%s: enter; is on=%u", fn, isOn); + tNFA_STATUS stat = NFA_STATUS_FAILED; + + mIsP2pListening = false; // In both cases, P2P will not be listening + + if (isOn) + { + // Start with no clients or servers + memset (mServers, 0, sizeof(mServers)); + memset (mClients, 0, sizeof(mClients)); + + //Android older than 4.0.3 (Ice Cream Sandwich) do not have SNEP in the + //NFC service, so the JNI and stack have to implement SNEP. + if (mJniVersion < 403) + { + { + SyncEventGuard guard (mSnepDefaultServerStartStopEvent); + stat = NFA_SnepStartDefaultServer (snepClientCallback); + if (stat == NFA_STATUS_OK) + mSnepDefaultServerStartStopEvent.wait (); //wait for NFA_SNEP_DEFAULT_SERVER_STARTED_EVT + else + ALOGE ("%s: fail start snep server; error=0x%X", fn, stat); + } + + { + SyncEventGuard guard (mSnepRegisterEvent); + stat = NFA_SnepRegisterClient (snepClientCallback); + if (stat == NFA_STATUS_OK) + mSnepRegisterEvent.wait (); //wait for NFA_SNEP_REG_EVT + else + ALOGE ("%s: fail register snep client; error=0x%X", fn, stat); + } + } + } + else + { + int ii = 0, jj = 0; + + // Disconnect through all the clients + for (ii = 0; ii < sMax; ii++) + { + if (mClients[ii] != NULL) + { + if (mClients[ii]->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) + { + SyncEventGuard guard (mClients[ii]->mConnectingEvent); + mClients[ii]->mConnectingEvent.notifyOne(); + } + else + { + mClients[ii]->mClientConn.mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mClients[ii]->mClientConn.mCongEvent); + mClients[ii]->mClientConn.mCongEvent.notifyOne (); //unblock send() + } + { + SyncEventGuard guard2 (mClients[ii]->mClientConn.mReadEvent); + mClients[ii]->mClientConn.mReadEvent.notifyOne (); //unblock receive() + } + } + } + } //loop + + // Now look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if (mServers[ii]->mServerConn[jj] != NULL) + { + mServers[ii]->mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mServers[ii]->mServerConn[jj]->mCongEvent); + mServers[ii]->mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested) + } + { + SyncEventGuard guard2 (mServers[ii]->mServerConn[jj]->mReadEvent); + mServers[ii]->mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive() + } + } + } + } + } //loop + + mJniHandleSendingNppViaSnep = 0; + mRcvFakeNppJniHandle = 0; + mSnepRegHandle = NFA_HANDLE_INVALID; + + if (mNppFakeOutBuffer != NULL) + { + free (mNppFakeOutBuffer); + mNppFakeOutBuffer = NULL; + } + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaServerCallback +** +** Description: Receive LLCP-related events from the stack. +** p2pEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) +{ + static const char fn [] = "PeerToPeer::nfaServerCallback"; + P2pServer *pSrv = NULL; + NfaConn *pConn = NULL; + + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent); + + switch (p2pEvent) + { + case NFA_P2P_LISTEN_EVT: // NFA_P2pRegisterServer() has started to listen + ALOGD ("%s: NFA_P2P_LISTEN_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, + eventData->listen.server_handle, eventData->listen.server_sap, eventData->listen.service_name); + + if ((pSrv = sP2p.findServer(eventData->listen.service_name)) == NULL) + { + ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service: %s", fn, eventData->listen.service_name); + } + else + { + SyncEventGuard guard (pSrv->mListenEvent); + pSrv->mNfaP2pServerHandle = eventData->listen.server_handle; + pSrv->mListenEvent.notifyOne(); //unblock registerServer() + } + break; + + case NFA_P2P_ACTIVATED_EVT: //remote device has activated + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); + break; + + case NFA_P2P_DEACTIVATED_EVT: + ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); + break; + + case NFA_P2P_CONN_REQ_EVT: + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; nfa server h=0x%04x; nfa conn h=0x%04x; remote sap=0x%02x", fn, + eventData->conn_req.server_handle, eventData->conn_req.conn_handle, eventData->conn_req.remote_sap); + + if ((pSrv = sP2p.findServer(eventData->conn_req.server_handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn); + return; + } + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u", fn, pSrv->mJniHandle); + + // Look for a connection block that is waiting (handle invalid) + if ((pConn = pSrv->findServerConnection(NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; server not listening", fn); + } + else + { + SyncEventGuard guard (pSrv->mConnRequestEvent); + pConn->mNfaConnHandle = eventData->conn_req.conn_handle; + pConn->mRemoteMaxInfoUnit = eventData->conn_req.remote_miu; + pConn->mRemoteRecvWindow = eventData->conn_req.remote_rw; + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u; conn jni h=%u; notify conn req", fn, pSrv->mJniHandle, pConn->mJniHandle); + pSrv->mConnRequestEvent.notifyOne(); //unblock accept() + } + break; + + case NFA_P2P_CONNECTED_EVT: + ALOGD ("%s: NFA_P2P_CONNECTED_EVT; h=0x%x remote sap=0x%X", fn, + eventData->connected.client_handle, eventData->connected.remote_sap); + break; + + case NFA_P2P_DISC_EVT: + ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason); + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle); + } + else + { + sP2p.mDisconnectMutex.lock (); + pConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); + SyncEventGuard guard3 (pConn->mDisconnectingEvent); + pConn->mDisconnectingEvent.notifyOne (); + ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn); + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne (); //unblock write (if congested) + ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn); + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne (); //unblock receive() + ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn); + } + sP2p.mDisconnectMutex.unlock (); + } + break; + + case NFA_P2P_DATA_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); + } + else + { + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + eventData->data.handle, eventData->data.remote_sap); + const int maxBufSize = 2 * 1024; + UINT8 buffer [maxBufSize]; + UINT32 actualDataLen = 0; + BOOLEAN isMoreData = TRUE; + while (isMoreData) + { + actualDataLen = 0; + isMoreData = FALSE; + tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) + pConn->mInboundQ.enqueue (buffer, actualDataLen); + } + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); + } + break; + + case NFA_P2P_CONGEST_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); + } + else + { + ALOGD ("%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + eventData->congest.handle, eventData->congest.is_congested); + + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } + break; + + default: + ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); + break; + } + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaClientCallback +** +** Description: Receive LLCP-related events from the stack. +** p2pEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) +{ + static const char fn [] = "PeerToPeer::nfaClientCallback"; + NfaConn *pConn = NULL; + P2pClient *pClient = NULL; + + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent); + + switch (p2pEvent) + { + case NFA_P2P_REG_CLIENT_EVT: + // Look for a client that is trying to register + if ((pClient = sP2p.findClient ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_REG_CLIENT_EVT: can't find waiting client", fn); + } + else + { + ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient); + + SyncEventGuard guard (pClient->mRegisteringEvent); + pClient->mNfaP2pClientHandle = eventData->reg_client.client_handle; + pClient->mRegisteringEvent.notifyOne(); + } + break; + + case NFA_P2P_ACTIVATED_EVT: + // Look for a client that is trying to register + if ((pClient = sP2p.findClient (eventData->activated.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_ACTIVATED_EVT: can't find client", fn); + } + else + { + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient); + } + break; + + case NFA_P2P_DEACTIVATED_EVT: + ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT: conn handle: 0x%X", fn, eventData->deactivated.handle); + break; + + case NFA_P2P_CONNECTED_EVT: + // Look for the client that is trying to connect + if ((pClient = sP2p.findClient (eventData->connected.client_handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONNECTED_EVT: can't find client: 0x%04x", fn, eventData->connected.client_handle); + } + else + { + ALOGD ("%s: NFA_P2P_CONNECTED_EVT; client_handle=0x%04x conn_handle: 0x%04x remote sap=0x%X pClient: 0x%p", fn, + eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient); + + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mClientConn.mNfaConnHandle = eventData->connected.conn_handle; + pClient->mClientConn.mRemoteMaxInfoUnit = eventData->connected.remote_miu; + pClient->mClientConn.mRemoteRecvWindow = eventData->connected.remote_rw; + pClient->mConnectingEvent.notifyOne(); //unblock createDataLinkConn() + } + break; + + case NFA_P2P_DISC_EVT: + ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason); + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL) + { + // If no connection, may be a client that is trying to connect + if ((pClient = sP2p.findClientCon ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle); + return; + } + // Unblock createDataLinkConn() + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mConnectingEvent.notifyOne(); + } + else + { + sP2p.mDisconnectMutex.lock (); + pConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); + SyncEventGuard guard3 (pConn->mDisconnectingEvent); + pConn->mDisconnectingEvent.notifyOne (); + ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn); + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); //unblock write (if congested) + ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn); + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); //unblock receive() + ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn); + } + sP2p.mDisconnectMutex.unlock (); + } + break; + + case NFA_P2P_DATA_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); + } + else + { + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + eventData->data.handle, eventData->data.remote_sap); + const int maxBufSize = 2 * 1024; + UINT8 buffer [maxBufSize]; + UINT32 actualDataLen = 0; + BOOLEAN isMoreData = TRUE; + while (isMoreData) + { + actualDataLen = 0; + isMoreData = FALSE; + tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) + pConn->mInboundQ.enqueue (buffer, actualDataLen); + } + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); + } + break; + + case NFA_P2P_CONGEST_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); + } + else + { + ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + eventData->congest.handle, eventData->congest.is_congested); + + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } + break; + + default: + ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); + break; + } +} + + +/******************************************************************************* +** +** Function: snepClientCallback +** +** Description: Receive SNEP-related events from the stack. +** snepEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData) +{ + static const char fn [] = "PeerToPeer::snepClientCallback"; + P2pClient *pClient; + + switch (snepEvent) + { + case NFA_SNEP_REG_EVT: + { + ALOGD ("%s NFA_SNEP_REG_EVT Status: %u Handle: 0x%X", fn, eventData->reg.status, eventData->reg.reg_handle); + SyncEventGuard guard (sP2p.mSnepRegisterEvent); + if (eventData->reg.status == NFA_STATUS_OK) + sP2p.mSnepRegHandle = eventData->reg.reg_handle; + sP2p.mSnepRegisterEvent.notifyOne (); + break; + } + + case NFA_SNEP_ACTIVATED_EVT: + ALOGD ("%s NFA_SNEP_ACTIVATED_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + break; + + case NFA_SNEP_DEACTIVATED_EVT: + ALOGD ("%s NFA_SNEP_ACTIVATED_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + break; + + case NFA_SNEP_CONNECTED_EVT: + if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) + { + ALOGE ("%s: NFA_SNEP_CONNECTED_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + } + else + { + ALOGD ("%s NFA_SNEP_CONNECTED_EVT mJniHandleSendingNppViaSnep: %u ConnHandle: 0x%04x", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->connect.conn_handle); + + pClient->mSnepConnHandle = eventData->connect.conn_handle; + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.notifyOne(); + } + break; + + case NFA_SNEP_PUT_RESP_EVT: + if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) + { + ALOGE ("%s: NFA_SNEP_PUT_RESP_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + } + else + { + ALOGD ("%s NFA_SNEP_PUT_RESP_EVT mJniHandleSendingNppViaSnep: %u Result: 0x%X", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->put_resp.resp_code); + + pClient->mIsSnepSentOk = (eventData->put_resp.resp_code == NFA_SNEP_RESP_CODE_SUCCESS); + + NFA_SnepDisconnect (eventData->put_resp.conn_handle, FALSE); + + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.notifyOne(); + } + break; + + case NFA_SNEP_DISC_EVT: + if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) + { + ALOGE ("%s: NFA_SNEP_DISC_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + } + else + { + ALOGD ("%s NFA_SNEP_DISC_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); + pClient->mSnepConnHandle = NFA_HANDLE_INVALID; + + SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepEvent.notifyOne(); + } + break; + + case NFA_SNEP_DEFAULT_SERVER_STARTED_EVT: + { + ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STARTED_EVT", fn); + SyncEventGuard guard (sP2p.mSnepDefaultServerStartStopEvent); + sP2p.mSnepDefaultServerStartStopEvent.notifyOne(); //unblock NFA_SnepStartDefaultServer() + break; + } + + case NFA_SNEP_DEFAULT_SERVER_STOPPED_EVT: + { + ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STOPPED_EVT", fn); + SyncEventGuard guard (sP2p.mSnepDefaultServerStartStopEvent); + sP2p.mSnepDefaultServerStartStopEvent.notifyOne(); //unblock NFA_SnepStopDefaultServer() + break; + } + break; + + default: + ALOGE ("%s UNKNOWN EVENT: 0x%04x mJniHandleSendingNppViaSnep: %u", fn, snepEvent, sP2p.mJniHandleSendingNppViaSnep); + break; + } +} + + +/******************************************************************************* +** +** Function: ndefTypeCallback +** +** Description: Receive NDEF-related events from the stack. +** ndefEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::ndefTypeCallback (tNFA_NDEF_EVT ndefEvent, tNFA_NDEF_EVT_DATA *eventData) +{ + static const char fn [] = "PeerToPeer::ndefTypeCallback"; + P2pServer *pSvr = NULL; + + if (ndefEvent == NFA_NDEF_REGISTER_EVT) + { + tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg; + ALOGD ("%s NFA_NDEF_REGISTER_EVT Status: %u; h=0x%X", fn, ndef_reg.status, ndef_reg.ndef_type_handle); + sP2p.mNdefTypeHandlerHandle = ndef_reg.ndef_type_handle; + } + else if (ndefEvent == NFA_NDEF_DATA_EVT) + { + ALOGD ("%s NFA_NDEF_DATA_EVT Len: %lu", fn, eventData->ndef_data.len); + + if (sP2p.mRcvFakeNppJniHandle != 0) + { + ALOGE ("%s Got NDEF Data while busy, mRcvFakeNppJniHandle: %u", fn, sP2p.mRcvFakeNppJniHandle); + return; + } + + if ((pSvr = sP2p.findServer ("com.android.npp")) == NULL) + { + ALOGE ("%s Got NDEF Data but no NPP server listening", fn); + return; + } + + if ((sP2p.mNppFakeOutBuffer = (UINT8 *)malloc(eventData->ndef_data.len + 10)) == NULL) + { + ALOGE ("%s failed to malloc: %lu bytes", fn, eventData->ndef_data.len + 10); + return; + } + + sP2p.mNppFakeOutBuffer[0] = 0x01; + sP2p.mNppFakeOutBuffer[1] = 0x00; + sP2p.mNppFakeOutBuffer[2] = 0x00; + sP2p.mNppFakeOutBuffer[3] = 0x00; + sP2p.mNppFakeOutBuffer[4] = 0x01; + sP2p.mNppFakeOutBuffer[5] = 0x01; + sP2p.mNppFakeOutBuffer[6] = (UINT8)(eventData->ndef_data.len >> 24); + sP2p.mNppFakeOutBuffer[7] = (UINT8)(eventData->ndef_data.len >> 16); + sP2p.mNppFakeOutBuffer[8] = (UINT8)(eventData->ndef_data.len >> 8); + sP2p.mNppFakeOutBuffer[9] = (UINT8)(eventData->ndef_data.len); + + memcpy (&sP2p.mNppFakeOutBuffer[10], eventData->ndef_data.p_data, eventData->ndef_data.len); + + ALOGD ("%s NFA_NDEF_DATA_EVT Faking NPP on Server Handle: %u", fn, pSvr->mJniHandle); + + sP2p.mRcvFakeNppJniHandle = pSvr->mJniHandle; + sP2p.mNppTotalLen = eventData->ndef_data.len + 10; + sP2p.mNppReadSoFar = 0; + { + SyncEventGuard guard (pSvr->mConnRequestEvent); + pSvr->mConnRequestEvent.notifyOne(); + } + } + else + { + ALOGE ("%s UNKNOWN EVENT: 0x%X", fn, ndefEvent); + } + +} + + +/******************************************************************************* +** +** Function: getLogLevel +** +** Description: Get the diagnostic logging level. +** +** Returns: Log level; 0=no logging; 1=error only; 5=debug +** +*******************************************************************************/ +UINT32 PeerToPeer::getLogLevel () +{ + return mAppLogLevel; +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Receive events from the stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + switch (event) + { + case NFA_SET_P2P_LISTEN_TECH_EVT: + { + SyncEventGuard guard (mSetTechEvent); + mSetTechEvent.notifyOne(); //unblock NFA_SetP2pListenTech() + break; + } + } +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: P2pServer +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +P2pServer::P2pServer() +: mNfaP2pServerHandle (NFA_HANDLE_INVALID), + mJniHandle (0) +{ + memset (mServerConn, 0, sizeof(mServerConn)); +} + + +/******************************************************************************* +** +** Function: findServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +NfaConn *P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) +{ + int jj = 0; + + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) + return (mServerConn[jj]); + } + + // If here, not found + return (NULL); +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: P2pClient +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +P2pClient::P2pClient () +: mNfaP2pClientHandle (NFA_HANDLE_INVALID), + mIsConnecting (false), + mSnepConnHandle (NFA_HANDLE_INVALID), + mSnepNdefMsgLen (0), + mSnepNdefBufLen (0), + mSnepNdefBuf (NULL), + mIsSnepSentOk (false) +{ +} + + +/******************************************************************************* +** +** Function: ~P2pClient +** +** Description: Free all resources. +** +** Returns: None +** +*******************************************************************************/ +P2pClient::~P2pClient () +{ + if (mSnepNdefBuf) + free (mSnepNdefBuf); +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: NfaConn +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +NfaConn::NfaConn() +: mNfaConnHandle (NFA_HANDLE_INVALID), + mJniHandle (0), + mMaxInfoUnit (0), + mRecvWindow (0), + mRemoteMaxInfoUnit (0), + mRemoteRecvWindow (0) +{ +} + diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h new file mode 100644 index 0000000..00ead7f --- /dev/null +++ b/nci/jni/PeerToPeer.h @@ -0,0 +1,705 @@ +/***************************************************************************** +** +** Name: PeerToPeer.h +** +** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "SyncEvent.h" +#include "DataQueue.h" +#include "NfcJniUtil.h" +#include +extern "C" +{ + #include "nfa_p2p_api.h" + #include "nfa_snep_api.h" +} + +class P2pServer; +class P2pClient; +class NfaConn; +#define MAX_NFA_CONNS_PER_SERVER 5 +typedef unsigned int tBRCM_JNI_HANDLE; + + +/***************************************************************************** +** +** Name: PeerToPeer +** +** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. +** +*****************************************************************************/ +class PeerToPeer +{ +public: + + + /******************************************************************************* + ** + ** Function: PeerToPeer + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + PeerToPeer (); + + + /******************************************************************************* + ** + ** Function: ~PeerToPeer + ** + ** Description: Free all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~PeerToPeer (); + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get the singleton PeerToPeer object. + ** + ** Returns: Singleton PeerToPeer object. + ** + *******************************************************************************/ + static PeerToPeer& getInstance(); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize member variables. + ** jniVersion: JNI version. + ** + ** Returns: None + ** + *******************************************************************************/ + void initialize (long jniVersion); + + + /******************************************************************************* + ** + ** Function: llcpActivatedHandler + ** + ** Description: Receive LLLCP-activated event from stack. + ** nat: JVM-related data. + ** activated: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void llcpActivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_ACTIVATED& activated); + + + /******************************************************************************* + ** + ** Function: llcpDeactivatedHandler + ** + ** Description: Receive LLLCP-deactivated event from stack. + ** nat: JVM-related data. + ** deactivated: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void llcpDeactivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_DEACTIVATED& deactivated); + + + /******************************************************************************* + ** + ** Function: connectionEventHandler + ** + ** Description: Receive events from the stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: registerServer + ** + ** Description: Let a server start listening for peer's connection request. + ** jniHandle: Connection handle. + ** serviceName: Server's service name. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool registerServer (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); + + + /******************************************************************************* + ** + ** Function: deregisterServer + ** + ** Description: Stop a P2pServer from listening for peer. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool deregisterServer (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: accept + ** + ** Description: Accept a peer's request to connect. + ** serverJniHandle: Server's handle. + ** connJniHandle: Connection handle. + ** maxInfoUnit: Maximum information unit. + ** recvWindow: Receive window size. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow); + + + /******************************************************************************* + ** + ** Function: createClient + ** + ** Description: Create a P2pClient object for a new out-bound connection. + ** jniHandle: Connection handle. + ** miu: Maximum information unit. + ** rw: Receive window size. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw); + + + /******************************************************************************* + ** + ** Function: connectConnOriented + ** + ** Description: Estabish a connection-oriented connection to a peer. + ** jniHandle: Connection handle. + ** serviceName: Peer's service name. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); + + + /******************************************************************************* + ** + ** Function: connectConnOriented + ** + ** Description: Estabish a connection-oriented connection to a peer. + ** jniHandle: Connection handle. + ** destinationSap: Peer's service access point. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap); + + + /******************************************************************************* + ** + ** Function: send + ** + ** Description: Send data to peer. + ** jniHandle: Handle of connection. + ** buffer: Buffer of data. + ** bufferLen: Length of data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool send (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen); + + + /******************************************************************************* + ** + ** Function: receive + ** + ** Description: Receive data from peer. + ** jniHandle: Handle of connection. + ** buffer: Buffer to store data. + ** bufferLen: Max length of buffer. + ** actualLen: Actual length received. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); + + + /******************************************************************************* + ** + ** Function: disconnectConnOriented + ** + ** Description: Disconnect a connection-oriented connection with peer. + ** jniHandle: Handle of connection. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: getRemoteMaxInfoUnit + ** + ** Description: Get peer's max information unit. + ** jniHandle: Handle of the connection. + ** + ** Returns: Peer's max information unit. + ** + *******************************************************************************/ + UINT16 getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: getRemoteRecvWindow + ** + ** Description: Get peer's receive window size. + ** jniHandle: Handle of the connection. + ** + ** Returns: Peer's receive window size. + ** + *******************************************************************************/ + UINT8 getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: enableP2pListening + ** + ** Description: Start/stop polling/listening to peer that supports P2P. + ** isEnable: Is enable polling/listening? + ** + ** Returns: None + ** + *******************************************************************************/ + void enableP2pListening (bool isEnable); + + + /******************************************************************************* + ** + ** Function: handleNfcOnOff + ** + ** Description: Handle events related to turning NFC on/off by the user. + ** isOn: Is NFC turning on? + ** + ** Returns: None + ** + *******************************************************************************/ + void handleNfcOnOff (bool isOn); + + + /******************************************************************************* + ** + ** Function: getLogLevel + ** + ** Description: Get the diagnostic logging level. + ** + ** Returns: Log level; 0=no logging; 1=error only; 5=debug + ** + *******************************************************************************/ + UINT32 getLogLevel (); + +private: + static const int sMax = 10; + static PeerToPeer sP2p; + static const std::string sSnepServiceName; + static const std::string sNppServiceName; + UINT16 mRemoteWKS; // Peer's well known services + bool mIsP2pListening; // If P2P listening is enabled or not + tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask + tBRCM_JNI_HANDLE mJniHandleSendingNppViaSnep; + tNFA_HANDLE mSnepRegHandle; + tBRCM_JNI_HANDLE mRcvFakeNppJniHandle; + UINT8 *mNppFakeOutBuffer; + UINT32 mNppTotalLen; + UINT32 mNppReadSoFar; + tNFA_HANDLE mNdefTypeHandlerHandle; + UINT32 mAppLogLevel; + long mJniVersion; + + P2pServer *mServers [sMax]; + P2pClient *mClients [sMax]; + SyncEvent mSetTechEvent; // completion event for NFA_SetP2pListenTech() + SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer() + SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient() + Mutex mDisconnectMutex; // synchronize the disconnect operation + + + /******************************************************************************* + ** + ** Function: nfaServerCallback + ** + ** Description: Receive LLCP-related events from the stack. + ** p2pEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); + + + /******************************************************************************* + ** + ** Function: nfaClientCallback + ** + ** Description: Receive LLCP-related events from the stack. + ** p2pEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); + + + /******************************************************************************* + ** + ** Function: snepClientCallback + ** + ** Description: Receive SNEP-related events from the stack. + ** snepEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData); + + + /******************************************************************************* + ** + ** Function: ndefTypeCallback + ** + ** Description: Receive NDEF-related events from the stack. + ** ndefEvent: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void ndefTypeCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *evetnData); + + + /******************************************************************************* + ** + ** Function: findServer + ** + ** Description: Find a PeerToPeer object by connection handle. + ** nfaP2pServerHandle: Connectin handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pServer *findServer (tNFA_HANDLE nfaP2pServerHandle); + + + /******************************************************************************* + ** + ** Function: findServer + ** + ** Description: Find a PeerToPeer object by connection handle. + ** serviceName: service name. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pServer *findServer (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: findServer + ** + ** Description: Find a PeerToPeer object by service name + ** serviceName: service name. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pServer *findServer (const char *serviceName); + + + /******************************************************************************* + ** + ** Function: removeServer + ** + ** Description: Free resources related to a server. + ** jniHandle: Connection handle. + ** + ** Returns: None + ** + *******************************************************************************/ + void removeServer (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: removeConn + ** + ** Description: Free resources related to a connection. + ** jniHandle: Connection handle. + ** + ** Returns: None + ** + *******************************************************************************/ + void removeConn (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: createDataLinkConn + ** + ** Description: Establish a connection-oriented connection to a peer. + ** jniHandle: Connection handle. + ** serviceName: Peer's service name. + ** destinationSap: Peer's service access point. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap); + + + /******************************************************************************* + ** + ** Function: findClient + ** + ** Description: Find a PeerToPeer object with a client connection handle. + ** nfaConnHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pClient *findClient (tNFA_HANDLE nfaConnHandle); + + + /******************************************************************************* + ** + ** Function: findClient + ** + ** Description: Find a PeerToPeer object with a client connection handle. + ** jniHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pClient *findClient (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: findClientCon + ** + ** Description: Find a PeerToPeer object with a client connection handle. + ** nfaConnHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + P2pClient *findClientCon (tNFA_HANDLE nfaConnHandle); + + + /******************************************************************************* + ** + ** Function: findConnection + ** + ** Description: Find a PeerToPeer object with a connection handle. + ** nfaConnHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + NfaConn *findConnection (tNFA_HANDLE nfaConnHandle); + + + /******************************************************************************* + ** + ** Function: findConnection + ** + ** Description: Find a PeerToPeer object with a connection handle. + ** jniHandle: Connection handle. + ** + ** Returns: PeerToPeer object. + ** + *******************************************************************************/ + NfaConn *findConnection (tBRCM_JNI_HANDLE jniHandle); + + + /******************************************************************************* + ** + ** Function: sendViaSnep + ** + ** Description: Send out-bound data to the stack's SNEP protocol. + ** jniHandle: Handle of connection. + ** buffer: Buffer of data. + ** dataLen: Length of data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen); + + + /******************************************************************************* + ** + ** Function: feedNppFromSnep + ** + ** Description: Send incomming data to the NFC service's NDEF Push Protocol. + ** buffer: Buffer of data to send. + ** bufferLen: Length of data in buffer. + ** actualLen: Actual length sent. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); +}; + + +/***************************************************************************** +** +** Name: NfaConn +** +** Description: Store information about a connection related to a peer. +** +*****************************************************************************/ +class NfaConn +{ +public: + tNFA_HANDLE mNfaConnHandle; // NFA handle of the P2P connection + tBRCM_JNI_HANDLE mJniHandle; // JNI handle of the P2P connection + UINT16 mMaxInfoUnit; + UINT8 mRecvWindow; + UINT16 mRemoteMaxInfoUnit; + UINT8 mRemoteRecvWindow; + DataQueue mInboundQ; // store inbound data + SyncEvent mReadEvent; // event for reading + SyncEvent mCongEvent; // event for congestion + SyncEvent mDisconnectingEvent; // event for disconnecting + + + /******************************************************************************* + ** + ** Function: NfaConn + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + NfaConn(); +}; + + +/***************************************************************************** +** +** Name: P2pServer +** +** Description: Store information about an in-bound connection from a peer. +** +*****************************************************************************/ +class P2pServer +{ +public: + tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server + tBRCM_JNI_HANDLE mJniHandle; // JNI Handle + SyncEvent mListenEvent; // for NFA_P2pRegisterServer() + SyncEvent mConnRequestEvent; // for accept() + std::string mServiceName; + NfaConn *mServerConn[MAX_NFA_CONNS_PER_SERVER]; + + /******************************************************************************* + ** + ** Function: P2pServer + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + P2pServer (); + + + /******************************************************************************* + ** + ** Function: findServerConnection + ** + ** Description: Find a P2pServer that has the handle. + ** nfaConnHandle: NFA connection handle. + ** + ** Returns: P2pServer object. + ** + *******************************************************************************/ + NfaConn *findServerConnection (tNFA_HANDLE nfaConnHandle); +}; + + +/***************************************************************************** +** +** Name: P2pClient +** +** Description: Store information about an out-bound connection to a peer. +** +*****************************************************************************/ +class P2pClient +{ +public: + tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client + bool mIsConnecting; // Set true while connecting + tNFA_HANDLE mSnepConnHandle; + UINT32 mSnepNdefMsgLen; // SNEP total NDEF message length + UINT32 mSnepNdefBufLen; // SNEP NDEF buffer length + UINT8 *mSnepNdefBuf; // SNEP NDEF Message + bool mIsSnepSentOk; // SNEP transmission status + NfaConn mClientConn; + SyncEvent mRegisteringEvent; // For client registration + SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap() + SyncEvent mSnepEvent; // To wait for SNEP completion + + /******************************************************************************* + ** + ** Function: P2pClient + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + P2pClient (); + + + /******************************************************************************* + ** + ** Function: ~P2pClient + ** + ** Description: Free all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~P2pClient (); +}; + diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp new file mode 100755 index 0000000..e5faaae --- /dev/null +++ b/nci/jni/PowerSwitch.cpp @@ -0,0 +1,410 @@ +/***************************************************************************** +** +** Name: PowerSwitch.cpp +** +** Description: Adjust the controller's power states. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include "PowerSwitch.h" +#include "NfcJniUtil.h" +#include "config.h" +#include "SecureElement.h" +#include "userial.h" + + +namespace android +{ + void doStartupConfig (); +} + + +PowerSwitch PowerSwitch::sPowerSwitch; + +/******************************************************************************* +** +** Function: PowerSwitch +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +PowerSwitch::PowerSwitch () +: mCurrLevel (UNKNOWN_LEVEL), + mScreenState (true), + mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN), + mDesiredScreenOffPowerState (0) +{ +} + + +/******************************************************************************* +** +** Function: ~PowerSwitch +** +** Description: Release all resources. +** +** Returns: None +** +*******************************************************************************/ +PowerSwitch::~PowerSwitch () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the singleton of this object. +** +** Returns: Reference to this object. +** +*******************************************************************************/ +PowerSwitch& PowerSwitch::getInstance () +{ + return sPowerSwitch; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +void PowerSwitch::initialize (PowerLevel level) +{ + static const char fn [] = "PowerSwitch::initialize"; + ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level); + + GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &mDesiredScreenOffPowerState, sizeof(mDesiredScreenOffPowerState)); + ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState); + + switch (level) + { + case FULL_POWER: + mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL; + mCurrLevel = level; + break; + + case UNKNOWN_LEVEL: + mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; + mCurrLevel = level; + break; + + default: + ALOGE ("%s: not handled", fn); + break; + } +} + + +/******************************************************************************* +** +** Function: getLevel +** +** Description: Get the current power level of the controller. +** +** Returns: Power level. +** +*******************************************************************************/ +PowerSwitch::PowerLevel PowerSwitch::getLevel () +{ + return mCurrLevel; +} + + +/******************************************************************************* +** +** Function: setLevel +** +** Description: Set the controller's power level. +** level: power level. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PowerSwitch::setLevel (PowerLevel newLevel) +{ + static const char fn [] = "PowerSwitch::setLevel"; + ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel); + bool retval = false; + + if (mCurrLevel == newLevel) + return true; + + switch (newLevel) + { + case FULL_POWER: + if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP) + retval = setPowerOffSleepState (false); + break; + + case LOW_POWER: + case POWER_OFF: + if (isPowerOffSleepFeatureEnabled()) + retval = setPowerOffSleepState (true); + else if (mDesiredScreenOffPowerState == 1) //.conf file desires full-power + { + mCurrLevel = FULL_POWER; + retval = true; + } + break; + + default: + ALOGE ("%s: not handled", fn); + break; + } + return retval; +} + +/******************************************************************************* +** +** Function: isScreenOn +** +** Description: Get the current platform power level. +** +** Returns: true if screen is on (locked or unlocked). +** +*******************************************************************************/ +bool PowerSwitch::isScreenOn () +{ + return mScreenState; +} + + +/******************************************************************************* +** +** Function: setScreenState +** +** Description: Set the Platform's screen state +** state: true for screen on, flase for screem off +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PowerSwitch::setScreenState(bool state) +{ + mScreenState = state; + return true; +} + +/******************************************************************************* +** +** Function: setPowerOffSleepState +** +** Description: Adjust controller's power-off-sleep state. +** sleep: whether to enter sleep state. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PowerSwitch::setPowerOffSleepState (bool sleep) +{ + static const char fn [] = "PowerSwitch::setPowerOffSleepState"; + ALOGD ("%s: enter; sleep=%u", fn, sleep); + tNFA_STATUS stat = NFA_STATUS_FAILED; + bool retval = false; + + if (sleep) //enter power-off-sleep state + { + //make sure the current power state is ON + if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP) + { + SyncEventGuard guard (mPowerStateEvent); + ALOGD ("%s: try power off", fn); + stat = NFA_PowerOffSleepMode (TRUE); + if (stat == NFA_STATUS_OK) + { + mPowerStateEvent.wait (); + mCurrLevel = LOW_POWER; + ALOGD ("%s: wait for userial close", fn); + int count = 0; + while (USERIAL_IsClosed() == FALSE) + { + //must wait for userial to close completely; + //otherwise there is a race condition when the next operation + //wants to go to full-power again; + count++; + usleep (5000); //5 milliseconds = 5 000 microseconds + } + ALOGD ("%s: userial close ok; count=%d", fn, count); + } + else + { + ALOGE ("%s: API fail; stat=0x%X", fn, stat); + goto TheEnd; + } + } + else + { + ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn, + deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); + goto TheEnd; + } + } + else //exit power-off-sleep state + { + //make sure the current power state is OFF + if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) + { + mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; + SyncEventGuard guard (mPowerStateEvent); + ALOGD ("%s: try full power", fn); + stat = NFA_PowerOffSleepMode (FALSE); + if (stat == NFA_STATUS_OK) + { + mPowerStateEvent.wait (); + if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) + { + ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn, + deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); + goto TheEnd; + } + android::doStartupConfig (); + mCurrLevel = FULL_POWER; + } + else + { + ALOGE ("%s: API fail; stat=0x%X", fn, stat); + goto TheEnd; + } + } + else + { + ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn, + deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); + goto TheEnd; + } + } + + retval = true; +TheEnd: + ALOGD ("%s: exit; return %u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: deviceMgtPowerStateToString +** +** Description: Decode power level to a string. +** deviceMgtPowerState: power level. +** +** Returns: Text representation of power level. +** +*******************************************************************************/ +const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState) +{ + switch (deviceMgtPowerState) + { + case NFA_DM_PWR_MODE_FULL: + return "DM-FULL"; + case NFA_DM_PWR_MODE_OFF_SLEEP: + return "DM-OFF"; + default: + return "DM-unknown????"; + } +} + + +/******************************************************************************* +** +** Function: powerLevelToString +** +** Description: Decode power level to a string. +** level: power level. +** +** Returns: Text representation of power level. +** +*******************************************************************************/ +const char* PowerSwitch::powerLevelToString (PowerLevel level) +{ + switch (level) + { + case UNKNOWN_LEVEL: + return "PS-UNKNOWN"; + case FULL_POWER: + return "PS-FULL"; + case LOW_POWER: + return "PS-LOW-POWER"; + case POWER_OFF: + return "PS-POWER-OFF"; + default: + return "PS-unknown????"; + } +} + + +/******************************************************************************* +** +** Function: abort +** +** Description: Abort and unblock currrent operation. +** +** Returns: None +** +*******************************************************************************/ +void PowerSwitch::abort () +{ + static const char fn [] = "PowerSwitch::abort"; + ALOGD ("%s", fn); + SyncEventGuard guard (mPowerStateEvent); + mPowerStateEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: deviceManagementCallback +** +** Description: Callback function for the stack. +** event: event ID. +** eventData: event's data. +** +** Returns: None +** +*******************************************************************************/ +void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData) +{ + static const char fn [] = "PowerSwitch::deviceManagementCallback"; + + switch (event) + { + case NFA_DM_PWR_MODE_CHANGE_EVT: + { + tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode; + ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=%u; device mgt power mode=%s (%u)", fn, + power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode), power_mode.power_mode); + SyncEventGuard guard (sPowerSwitch.mPowerStateEvent); + if (power_mode.status == NFA_STATUS_OK) + sPowerSwitch.mCurrDeviceMgtPowerState = power_mode.power_mode; + sPowerSwitch.mPowerStateEvent.notifyOne (); + } + break; + } +} + + +/******************************************************************************* +** +** Function: isPowerOffSleepFeatureEnabled +** +** Description: Whether power-off-sleep feature is enabled in .conf file. +** +** Returns: True if feature is enabled. +** +*******************************************************************************/ +bool PowerSwitch::isPowerOffSleepFeatureEnabled () +{ + return mDesiredScreenOffPowerState == 0; +} + diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h new file mode 100755 index 0000000..09197f1 --- /dev/null +++ b/nci/jni/PowerSwitch.h @@ -0,0 +1,236 @@ +/***************************************************************************** +** +** Name: PowerSwitch.h +** +** Description: Adjust the controller's power states. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "nfa_api.h" +#include "nfa_brcm_api.h" +#include "SyncEvent.h" + + +/***************************************************************************** +** +** Name: PowerSwitch +** +** Description: Adjust the controller's power states. +** +*****************************************************************************/ +class PowerSwitch +{ +public: + + + /******************************************************************************* + ** + ** Description: UNKNOWN_LEVEL: power level is unknown because the stack is off. + ** FULL_POWER: controller is in full-power state. + ** LOW_POWER: controller is in lower-power state. + ** + *******************************************************************************/ + enum PowerLevel {UNKNOWN_LEVEL, FULL_POWER, LOW_POWER, POWER_OFF}; + + /******************************************************************************* + ** + ** Description: Platform Power Level, copied from NativeNfcBrcmPowerMode.java. + ** UNKNOWN_LEVEL: power level is unknown. + ** POWER_OFF: The phone is turned OFF + ** SCREEN_OFF: The phone is turned ON but screen is OFF + ** SCREEN_ON_LOCKED: The phone is turned ON, screen is ON but user locked + ** SCREEN_ON_UNLOCKED: The phone is turned ON, screen is ON, and user unlocked + ** + *******************************************************************************/ + static const int PLATFORM_UNKNOWN_LEVEL = 0; + static const int PLATFORM_POWER_OFF = 1; + static const int PLATFORM_SCREEN_OFF = 2; + static const int PLATFORM_SCREEN_ON_LOCKED = 3; + static const int PLATFORM_SCREEN_ON_UNLOCKED = 4; + + static const int VBAT_MONITOR_ENABLED = 1; + static const int VBAT_MONITOR_PRIMARY_THRESHOLD = 5; + static const int VBAT_MONITOR_SECONDARY_THRESHOLD = 8; + /******************************************************************************* + ** + ** Function: PowerSwitch + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + PowerSwitch (); + + + /******************************************************************************* + ** + ** Function: ~PowerSwitch + ** + ** Description: Release all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~PowerSwitch (); + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get the singleton of this object. + ** + ** Returns: Reference to this object. + ** + *******************************************************************************/ + static PowerSwitch& getInstance (); + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + void initialize (PowerLevel level); + + + /******************************************************************************* + ** + ** Function: getLevel + ** + ** Description: Get the current power level of the controller. + ** + ** Returns: Power level. + ** + *******************************************************************************/ + PowerLevel getLevel (); + + + /******************************************************************************* + ** + ** Function: isScreenOn + ** + ** Description: Get the current screen state of the platform host. + ** + ** Returns: true if screen if on, (locked or unlocked). + ** + *******************************************************************************/ + bool isScreenOn (); + + + /******************************************************************************* + ** + ** Function: setLevel + ** + ** Description: Set the controller's power level. + ** level: power level. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool setLevel (PowerLevel level); + + /******************************************************************************* + ** + ** Function: setScreenState + ** + ** Description: Set the Platform's screen state + ** state: true for screen on, flase for screem off + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool setScreenState (bool state); + + /******************************************************************************* + ** + ** Function: abort + ** + ** Description: Abort and unblock currrent operation. + ** + ** Returns: None + ** + *******************************************************************************/ + void abort (); + + + /******************************************************************************* + ** + ** Function: deviceManagementCallback + ** + ** Description: Callback function for the stack. + ** event: event ID. + ** eventData: event's data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: isPowerOffSleepFeatureEnabled + ** + ** Description: Whether power-off-sleep feature is enabled in .conf file. + ** + ** Returns: True if feature is enabled. + ** + *******************************************************************************/ + bool isPowerOffSleepFeatureEnabled (); + +private: + PowerLevel mCurrLevel; + bool mScreenState; + UINT8 mCurrDeviceMgtPowerState; //device management power state; such as NFA_DM_PWR_STATE_??? + int mDesiredScreenOffPowerState; //read from .conf file; 0=power-off-sleep; 1=full power; 2=CE4 power + static PowerSwitch sPowerSwitch; //singleton object + static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown + SyncEvent mPowerStateEvent; + + + /******************************************************************************* + ** + ** Function: setPowerOffSleepState + ** + ** Description: Adjust controller's power-off-sleep state. + ** sleep: whether to enter sleep state. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool setPowerOffSleepState (bool sleep); + + + /******************************************************************************* + ** + ** Function: deviceMgtPowerStateToString + ** + ** Description: Decode power level to a string. + ** deviceMgtPowerState: power level. + ** + ** Returns: Text representation of power level. + ** + *******************************************************************************/ + const char* deviceMgtPowerStateToString (UINT8 deviceMgtPowerState); + + + /******************************************************************************* + ** + ** Function: powerLevelToString + ** + ** Description: Decode power level to a string. + ** level: power level. + ** + ** Returns: Text representation of power level. + ** + *******************************************************************************/ + const char* powerLevelToString (PowerLevel level); +}; diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp new file mode 100644 index 0000000..6f6eff7 --- /dev/null +++ b/nci/jni/RouteDataSet.cpp @@ -0,0 +1,546 @@ +/***************************************************************************** +** +** Name: RouteDataSet.cpp +** +** Description: Import and export general routing data using a XML file. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ + +#include "RouteDataSet.h" +#include "libxml/xmlmemory.h" +#include +#include + +extern char bcm_nfc_location[]; + + +/******************************************************************************* +** +** Function: AidBuffer +** +** Description: Parse a string of hex numbers. Store result in an array of +** bytes. +** aid: string of hex numbers. +** +** Returns: None. +** +*******************************************************************************/ +AidBuffer::AidBuffer (std::string& aid) +: mBuffer (NULL), + mBufferLen (0) +{ + unsigned int num = 0; + const char delimiter = ':'; + std::string::size_type pos1 = 0; + std::string::size_type pos2 = aid.find_first_of (delimiter); + + //parse the AID string; each hex number is separated by a colon; + mBuffer = new UINT8 [aid.length()]; + while (true) + { + num = 0; + if (pos2 == std::string::npos) + { + sscanf (aid.substr(pos1).c_str(), "%x", &num); + mBuffer [mBufferLen] = (UINT8) num; + mBufferLen++; + break; + } + else + { + sscanf (aid.substr(pos1, pos2-pos1+1).c_str(), "%x", &num); + mBuffer [mBufferLen] = (UINT8) num; + mBufferLen++; + pos1 = pos2 + 1; + pos2 = aid.find_first_of (delimiter, pos1); + } + } +} + + +/******************************************************************************* +** +** Function: ~AidBuffer +** +** Description: Release all resources. +** +** Returns: None. +** +*******************************************************************************/ +AidBuffer::~AidBuffer () +{ + delete [] mBuffer; +} + + +/*******************************************************************************/ +/*******************************************************************************/ + + +const char* RouteDataSet::sConfigFile = "/param/route.xml"; + + +/******************************************************************************* +** +** Function: ~RouteDataSet +** +** Description: Release all resources. +** +** Returns: None. +** +*******************************************************************************/ +RouteDataSet::~RouteDataSet () +{ + deleteDatabase (); +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize resources. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool RouteDataSet::initialize () +{ + static const char fn [] = "RouteDataSet::initialize"; + ALOGD ("%s: enter", fn); + //check that the libxml2 version in use is compatible + //with the version the software has been compiled with + LIBXML_TEST_VERSION + ALOGD ("%s: exit; return=true", fn); + return true; +} + + +/******************************************************************************* +** +** Function: deleteDatabase +** +** Description: Delete all routes stored in all databases. +** +** Returns: None. +** +*******************************************************************************/ +void RouteDataSet::deleteDatabase () +{ + static const char fn [] = "RouteDataSet::deleteDatabase"; + ALOGD ("%s: default db size=%u; sec elem db size=%u", fn, mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size()); + Database::iterator it; + + for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++) + delete (*it); + mDefaultRouteDatabase.clear (); + + for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end(); it++) + delete (*it); + mSecElemRouteDatabase.clear (); +} + + +/******************************************************************************* +** +** Function: import +** +** Description: Import data from an XML file. Fill the databases. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool RouteDataSet::import () +{ + static const char fn [] = "RouteDataSet::import"; + ALOGD ("%s: enter", fn); + bool retval = false; + xmlDocPtr doc; + xmlNodePtr node1; + std::string strFilename(bcm_nfc_location); + strFilename += sConfigFile; + + deleteDatabase (); + + doc = xmlParseFile (strFilename.c_str()); + if (doc == NULL) + { + ALOGD ("%s: fail parse", fn); + goto TheEnd; + } + + node1 = xmlDocGetRootElement (doc); + if (node1 == NULL) + { + ALOGE ("%s: fail root element", fn); + goto TheEnd; + } + ALOGD ("%s: root=%s", fn, node1->name); + + node1 = node1->xmlChildrenNode; + while (node1) //loop through all elements in name, (const xmlChar*) "Route")==0) + { + xmlChar* value = xmlGetProp (node1, (const xmlChar*) "Type"); + if (value && (xmlStrcmp (value, (const xmlChar*) "SecElemSelectedRoutes") == 0)) + { + ALOGD ("%s: found SecElemSelectedRoutes", fn); + xmlNodePtr node2 = node1->xmlChildrenNode; + while (node2) //loop all elements in name, (const xmlChar*) "Proto")==0) + importProtocolRoute (node2, mSecElemRouteDatabase); + else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0) + importTechnologyRoute (node2, mSecElemRouteDatabase); + node2 = node2->next; + } //loop all elements in xmlChildrenNode; + while (node2) //loop all elements in name, (const xmlChar*) "Proto")==0) + importProtocolRoute (node2, mDefaultRouteDatabase); + else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0) + importTechnologyRoute (node2, mDefaultRouteDatabase); + node2 = node2->next; + } //loop all elements in next; + } //loop through all elements in name); + value = xmlGetProp (element, id); + if (value) + { + if (xmlStrcmp (value, (const xmlChar*) "T1T") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_T1T; + else if (xmlStrcmp (value, (const xmlChar*) "T2T") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_T2T; + else if (xmlStrcmp (value, (const xmlChar*) "T3T") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_T3T; + else if (xmlStrcmp (value, (const xmlChar*) "IsoDep") == 0) + data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP; + xmlFree (value); + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mProtocol); + } + + value = xmlGetProp (element, secElem); + if (value) + { + data->mNfaEeHandle = strtol ((char*) value, NULL, 16); + xmlFree (value); + data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE; + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle); + } + + value = xmlGetProp (element, switchOn); + if (value) + { + data->mSwitchOn = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, switchOff); + if (value) + { + data->mSwitchOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, batteryOff); + if (value) + { + data->mBatteryOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + database.push_back (data); +} + + +/******************************************************************************* +** +** Function: importTechnologyRoute +** +** Description: Parse data for technology routes. +** element: XML node for one technology route. +** database: store data in this database. +** +** Returns: None. +** +*******************************************************************************/ +void RouteDataSet::importTechnologyRoute (xmlNodePtr& element, Database& database) +{ + static const char fn [] = "RouteDataSet::importTechnologyRoute"; + const xmlChar* id = (const xmlChar*) "Id"; + const xmlChar* secElem = (const xmlChar*) "SecElem"; + const xmlChar* trueString = (const xmlChar*) "true"; + const xmlChar* switchOn = (const xmlChar*) "SwitchOn"; + const xmlChar* switchOff = (const xmlChar*) "SwitchOff"; + const xmlChar* batteryOff = (const xmlChar*) "BatteryOff"; + RouteDataForTechnology* data = new RouteDataForTechnology; + xmlChar* value = NULL; + + ALOGD_IF (sDebug, "%s: element=%s", fn, element->name); + value = xmlGetProp (element, id); + if (value) + { + if (xmlStrcmp (value, (const xmlChar*) "NfcA") == 0) + data->mTechnology = NFA_TECHNOLOGY_MASK_A; + else if (xmlStrcmp (value, (const xmlChar*) "NfcB") == 0) + data->mTechnology = NFA_TECHNOLOGY_MASK_B; + else if (xmlStrcmp (value, (const xmlChar*) "NfcF") == 0) + data->mTechnology = NFA_TECHNOLOGY_MASK_F; + xmlFree (value); + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mTechnology); + } + + value = xmlGetProp (element, secElem); + if (value) + { + data->mNfaEeHandle = strtol ((char*) value, NULL, 16); + xmlFree (value); + data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE; + ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle); + } + + value = xmlGetProp (element, switchOn); + if (value) + { + data->mSwitchOn = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, switchOff); + if (value) + { + data->mSwitchOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + + value = xmlGetProp (element, batteryOff); + if (value) + { + data->mBatteryOff = (xmlStrcmp (value, trueString) == 0); + xmlFree (value); + } + database.push_back (data); +} + + +/******************************************************************************* +** +** Function: deleteFile +** +** Description: Delete route data XML file. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool RouteDataSet::deleteFile () +{ + static const char fn [] = "RouteDataSet::deleteFile"; + std::string filename (bcm_nfc_location); + filename.append (sConfigFile); + int stat = remove (filename.c_str()); + ALOGD ("%s: exit %u", fn, stat==0); + return stat == 0; +} + + +/******************************************************************************* +** +** Function: getDatabase +** +** Description: Obtain a database of routing data. +** selection: which database. +** +** Returns: Pointer to database. +** +*******************************************************************************/ +RouteDataSet::Database* RouteDataSet::getDatabase (DatabaseSelection selection) +{ + switch (selection) + { + case DefaultRouteDatabase: + return &mDefaultRouteDatabase; + case SecElemRouteDatabase: + return &mSecElemRouteDatabase; + } + return NULL; +} + + +/******************************************************************************* +** +** Function: printDiagnostic +** +** Description: Print some diagnostic output. +** +** Returns: None. +** +*******************************************************************************/ +void RouteDataSet::printDiagnostic () +{ + static const char fn [] = "RouteDataSet::printDiagnostic"; + Database* db = getDatabase (DefaultRouteDatabase); + + ALOGD ("%s: default route database", fn); + for (Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + switch (routeData->mRouteType) + { + case RouteData::ProtocolRoute: + { + RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData; + ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol); + } + break; + } + } + + ALOGD ("%s: sec elem route database", fn); + db = getDatabase (SecElemRouteDatabase); + for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++) + { + RouteData* routeData = *iter2; + switch (routeData->mRouteType) + { + case RouteData::ProtocolRoute: + { + RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData; + ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol); + } + break; + case RouteData::TechnologyRoute: + { + RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData; + ALOGD ("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology); + } + break; + } + } +} diff --git a/nci/jni/RouteDataSet.h b/nci/jni/RouteDataSet.h new file mode 100644 index 0000000..23fd958 --- /dev/null +++ b/nci/jni/RouteDataSet.h @@ -0,0 +1,299 @@ +/***************************************************************************** +** +** Name: RouteDataSet.h +** +** Description: Import and export general routing data using a XML file. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "NfcJniUtil.h" +#include "nfa_api.h" +#include +#include +#include + + +/***************************************************************************** +** +** Name: RouteData +** +** Description: Base class for every kind of route data. +** +*****************************************************************************/ +class RouteData +{ +public: + enum RouteType {ProtocolRoute, TechnologyRoute}; + RouteType mRouteType; + +protected: + RouteData (RouteType routeType) : mRouteType (routeType) + {} +}; + + + + +/***************************************************************************** +** +** Name: RouteDataForProtocol +** +** Description: Data for protocol routes. +** +*****************************************************************************/ +class RouteDataForProtocol : public RouteData +{ +public: + int mNfaEeHandle; //for example 0x4f3, 0x4f4 + bool mSwitchOn; + bool mSwitchOff; + bool mBatteryOff; + tNFA_PROTOCOL_MASK mProtocol; + + RouteDataForProtocol () : RouteData (ProtocolRoute), mNfaEeHandle (NFA_HANDLE_INVALID), + mSwitchOn (false), mSwitchOff (false), mBatteryOff (false), + mProtocol (0) + {} +}; + + +/***************************************************************************** +** +** Name: RouteDataForTechnology +** +** Description: Data for technology routes. +** +*****************************************************************************/ +class RouteDataForTechnology : public RouteData +{ +public: + int mNfaEeHandle; //for example 0x4f3, 0x4f4 + bool mSwitchOn; + bool mSwitchOff; + bool mBatteryOff; + tNFA_TECHNOLOGY_MASK mTechnology; + + RouteDataForTechnology () : RouteData (TechnologyRoute), mNfaEeHandle (NFA_HANDLE_INVALID), + mSwitchOn (false), mSwitchOff (false), mBatteryOff (false), + mTechnology (0) + {} +}; + + +/*****************************************************************************/ +/*****************************************************************************/ + + +/***************************************************************************** +** +** Name: AidBuffer +** +** Description: Buffer to store AID after converting a string of hex +** values to bytes. +** +*****************************************************************************/ +class AidBuffer +{ +public: + + /******************************************************************************* + ** + ** Function: AidBuffer + ** + ** Description: Parse a string of hex numbers. Store result in an array of + ** bytes. + ** aid: string of hex numbers. + ** + ** Returns: None. + ** + *******************************************************************************/ + AidBuffer (std::string& aid); + + + /******************************************************************************* + ** + ** Function: ~AidBuffer + ** + ** Description: Release all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~AidBuffer (); + + + UINT8* buffer () {return mBuffer;}; + int length () {return mBufferLen;}; + +private: + UINT8* mBuffer; + UINT32 mBufferLen; +}; + + +/*****************************************************************************/ +/*****************************************************************************/ + + +/***************************************************************************** +** +** Name: RouteDataSet +** +** Description: Import and export general routing data using a XML file. +** See /data/bcmnfc/param/route.xml +** +*****************************************************************************/ +class RouteDataSet +{ +public: + typedef std::vector Database; + enum DatabaseSelection {DefaultRouteDatabase, SecElemRouteDatabase}; + + + /******************************************************************************* + ** + ** Function: ~RouteDataSet + ** + ** Description: Release all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~RouteDataSet (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize resources. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool initialize (); + + + /******************************************************************************* + ** + ** Function: import + ** + ** Description: Import data from an XML file. Fill the database. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool import (); + + + /******************************************************************************* + ** + ** Function: getDatabase + ** + ** Description: Obtain a database of routing data. + ** selection: which database. + ** + ** Returns: Pointer to database. + ** + *******************************************************************************/ + Database* getDatabase (DatabaseSelection selection); + + + /******************************************************************************* + ** + ** Function: saveToFile + ** + ** Description: Save XML data from a string into a file. + ** routesXml: XML that represents routes. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + static bool saveToFile (const char* routesXml); + + + /******************************************************************************* + ** + ** Function: loadFromFile + ** + ** Description: Load XML data from file into a string. + ** routesXml: string to receive XML data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + static bool loadFromFile (std::string& routesXml); + + + /******************************************************************************* + ** + ** Function: deleteFile + ** + ** Description: Delete route data XML file. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + static bool deleteFile (); + + /******************************************************************************* + ** + ** Function: printDiagnostic + ** + ** Description: Print some diagnostic output. + ** + ** Returns: None. + ** + *******************************************************************************/ + void printDiagnostic (); + +private: + Database mSecElemRouteDatabase; //routes when NFC service selects sec elem + Database mDefaultRouteDatabase; //routes when NFC service deselects sec elem + static const char* sConfigFile; + static const bool sDebug = false; + + + /******************************************************************************* + ** + ** Function: deleteDatabase + ** + ** Description: Delete all routes stored in all databases. + ** + ** Returns: None. + ** + *******************************************************************************/ + void deleteDatabase (); + + + /******************************************************************************* + ** + ** Function: importProtocolRoute + ** + ** Description: Parse data for protocol routes. + ** element: XML node for one protocol route. + ** database: store data in this database. + ** + ** Returns: None. + ** + *******************************************************************************/ + void importProtocolRoute (xmlNodePtr& element, Database& database); + + + /******************************************************************************* + ** + ** Function: importTechnologyRoute + ** + ** Description: Parse data for technology routes. + ** element: XML node for one technology route. + ** database: store data in this database. + ** + ** Returns: None. + ** + *******************************************************************************/ + void importTechnologyRoute (xmlNodePtr& element, Database& database); +}; + diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp new file mode 100755 index 0000000..f518650 --- /dev/null +++ b/nci/jni/SecureElement.cpp @@ -0,0 +1,1987 @@ +/***************************************************************************** +** +** Name: SecureElement.cpp +** +** Description: Communicate with secure elements that are attached +** to the NFC controller. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#include +#include +#include "SecureElement.h" +#include "config.h" +#include "PowerSwitch.h" +#include "HostAidRouter.h" +#include "nfa_vs_brcm_api.h" + + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyTransactionListeners; + extern jmethodID gCachedNfcManagerNotifySeFieldActivated; + extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated; +} + + +/***************************************************************************** +** +** public variables +** +*****************************************************************************/ +int gSEId = -1; // secure element ID to use in connectEE(), -1 means not set +int gGatePipe = -1; // gate id or static pipe id to use in connectEE(), -1 means not set +bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if false, use as gate id + + +////////////////////////////////////////////// +////////////////////////////////////////////// + + +SecureElement SecureElement::sSecElem; + + +/******************************************************************************* +** +** Function: SecureElement +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +SecureElement::SecureElement () +: mActiveEeHandle (NFA_HANDLE_INVALID), + mDestinationGate (4), //loopback gate + mNfaHciHandle (NFA_HANDLE_INVALID), + mNativeData (NULL), + mIsInit (false), + mActualNumEe (0), + mNumEePresent(0), + mbNewEE (true), // by default we start w/thinking there are new EE + mNewPipeId (0), + mNewSourceGate (0), + mActiveSeOverride(0), + mCommandStatus (NFA_STATUS_OK), + mIsPiping (false), + mCurrentRouteSelection (NoRoute), + mTransDataSize(0) +{ + memset (&mEeInfo, 0, sizeof(mEeInfo)); + memset (&mUiccInfo, 0, sizeof(mUiccInfo)); + memset (&mHciCfg, 0, sizeof(mHciCfg)); + memset (mTransData, 0, MAX_TRANS_RECV_SIZE); +} + + +/******************************************************************************* +** +** Function: ~SecureElement +** +** Description: Release all resources. +** +** Returns: None +** +*******************************************************************************/ +SecureElement::~SecureElement () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the SecureElement singleton object. +** +** Returns: SecureElement object. +** +*******************************************************************************/ +SecureElement& SecureElement::getInstance() +{ + return sSecElem; +} + + +/******************************************************************************* +** +** Function: setActiveSeOverride +** +** Description: Specify which secure element to turn on. +** activeSeOverride: ID of secure element +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::setActiveSeOverride(UINT8 activeSeOverride) +{ + ALOGD ("SecureElement::setActiveSeOverride, seid=0x%X", activeSeOverride); + mActiveSeOverride = activeSeOverride; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize all member variables. +** native: Native data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::initialize (nfc_jni_native_data* native) +{ + static const char fn [] = "SecureElement::initialize"; + tNFA_STATUS nfaStat; + UINT8 xx = 0, yy = 0; + unsigned long num = 0; + + ALOGD ("%s: enter", fn); + + if (GetNumValue("NFA_HCI_DEFAULT_DEST_GATE", &num, sizeof(num))) + mDestinationGate = num; + ALOGD ("%s: Default destination gate: %d", __FUNCTION__, mDestinationGate); + + // active SE, if not set active all SEs + if (GetNumValue("ACTIVE_SE", &num, sizeof(num))) + mActiveSeOverride = num; + ALOGD ("%s: Active SE override: %d", __FUNCTION__, mActiveSeOverride); + + mActiveEeHandle = NFA_HANDLE_INVALID; + mNfaHciHandle = NFA_HANDLE_INVALID; + + mNativeData = native; + mActualNumEe = MAX_NUM_EE; + mbNewEE = true; + mNewPipeId = 0; + mNewSourceGate = 0; + mCurrentRouteSelection = NoRoute; + memset (mEeInfo, 0, sizeof(mEeInfo)); + memset (&mUiccInfo, 0, sizeof(mUiccInfo)); + memset (&mHciCfg, 0, sizeof(mHciCfg)); + mUsedAids.clear (); + + // Get Fresh EE info. + if (! getEeInfo()) + return (false); + + { + SyncEventGuard guard (mEeRegisterEvent); + ALOGD ("%s: try ee register", fn); + nfaStat = NFA_EeRegister (nfaEeCallback); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail ee register; error=0x%X", fn, nfaStat); + return (false); + } + mEeRegisterEvent.wait (); + } + + // If the controller has an HCI Network, register for that + for (xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface > 0) && (mEeInfo[xx].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + { + ALOGD ("%s: Found HCI network, try hci register", fn); + + SyncEventGuard guard (mHciRegisterEvent); + + nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE, MAX_TRANS_RECV_SIZE, mHciBufferForStack); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); + return (false); + } + mHciRegisterEvent.wait(); + break; + } + } + + mRouteDataSet.initialize (); + mRouteDataSet.import (); //read XML file + HostAidRouter::getInstance().initialize (); + + mIsInit = true; + ALOGD ("%s: exit", fn); + return (true); +} + + +/******************************************************************************* +** +** Function: finalize +** +** Description: Release all resources. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::finalize () +{ + static const char fn [] = "SecureElement::finalize"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + + NFA_EeDeregister (nfaEeCallback); + + if (mNfaHciHandle != NFA_HANDLE_INVALID) + NFA_HciDeregister ("brcm_jni"); + + mNfaHciHandle = NFA_HANDLE_INVALID; + mNativeData = NULL; + mIsInit = false; + mActualNumEe = 0; + mNumEePresent = 0; + mNewPipeId = 0; + mNewSourceGate = 0; + mIsPiping = false; + memset (mEeInfo, 0, sizeof(mEeInfo)); + memset (&mUiccInfo, 0, sizeof(mUiccInfo)); + + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: getEeInfo +** +** Description: Get latest information about execution environments from stack. +** +** Returns: True if at least 1 EE is available. +** +*******************************************************************************/ +bool SecureElement::getEeInfo() +{ + static const char fn [] = "SecureElement::getEeInfo"; + ALOGD ("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + UINT8 xx = 0, yy = 0; + + // If mbNewEE is true then there is new EE info. + if (mbNewEE) + { + mActualNumEe = MAX_NUM_EE; + + if ((nfaStat = NFA_EeGetInfo (&mActualNumEe, mEeInfo)) != NFA_STATUS_OK) + { + ALOGE ("%s: fail get info; error=0x%X", fn, nfaStat); + mActualNumEe = 0; + } + else + { + mbNewEE = false; + + ALOGD ("%s: num EEs discovered: %u", fn, mActualNumEe); + if (mActualNumEe != 0) + { + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + mNumEePresent++; + + ALOGD ("%s: EE[%u] Handle: 0x%04x Status: %s Num I/f: %u: (0x%02x, 0x%02x) Num TLVs: %u", + fn, xx, mEeInfo[xx].ee_handle, eeStatusToString(mEeInfo[xx].ee_status), mEeInfo[xx].num_interface, + mEeInfo[xx].ee_interface[0], mEeInfo[xx].ee_interface[1], mEeInfo[xx].num_tlvs); + + for (yy = 0; yy < mEeInfo[xx].num_tlvs; yy++) + { + ALOGD ("%s: EE[%u] TLV[%u] Tag: 0x%02x Len: %u Values[]: 0x%02x 0x%02x 0x%02x ...", + fn, xx, yy, mEeInfo[xx].ee_tlv[yy].tag, mEeInfo[xx].ee_tlv[yy].len, mEeInfo[xx].ee_tlv[yy].info[0], + mEeInfo[xx].ee_tlv[yy].info[1], mEeInfo[xx].ee_tlv[yy].info[2]); + } + } + } + } + } + ALOGD ("%s: exit; mActualNumEe=%d, mNumEePresent=%d", fn, mActualNumEe,mNumEePresent); + return (mActualNumEe != 0); +} + + +/******************************************************************************* +** +** Function: getListOfEeHandles +** +** Description: Get the list of handles of all execution environments. +** e: Java Virtual Machine. +** +** Returns: List of handles of all execution environments. +** +*******************************************************************************/ +jintArray SecureElement::getListOfEeHandles (JNIEnv* e) +{ + static const char fn [] = "SecureElement::getListOfEeHandles"; + ALOGD ("%s: enter", fn); + if (mNumEePresent == 0) + return NULL; + jintArray list = NULL; + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + return (NULL); + } + + // Get Fresh EE info. + if (! getEeInfo()) + return (NULL); + + list = e->NewIntArray (mNumEePresent); //allocate array + jint jj = 0; + int cnt = 0; + for (int ii = 0; ii < mActualNumEe && cnt < mNumEePresent; ii++) + { + ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle); + if ((mEeInfo[ii].num_interface == 0) || (mEeInfo[ii].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + { + continue; + } + + jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE; + e->SetIntArrayRegion (list, cnt++, 1, &jj); + } + //e->DeleteLocalRef (list); + + ALOGD("%s: exit", fn); + return list; +} + + +/******************************************************************************* +** +** Function: activate +** +** Description: Turn on the secure element. +** seID: ID of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::activate (jint seID) +{ + static const char fn [] = "SecureElement::activate"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + int numActivatedEe = 0; + + ALOGD ("%s: enter; seID=0x%X", fn, seID); + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + return false; + } + + if (mActiveEeHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: already active", fn); + return true; + } + + // Get Fresh EE info if needed. + if (! getEeInfo()) + { + ALOGE ("%s: no EE info", fn); + return false; + } + + mActiveEeHandle = getDefaultEeHandle(); + ALOGD ("%s: active ee h=0x%X, override se=0x%X", fn, mActiveEeHandle, mActiveSeOverride); + if (mActiveEeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: ee not found", fn); + return false; + } + + UINT16 override_se = 0; + if (mActiveSeOverride) + override_se = NFA_HANDLE_GROUP_EE | mActiveSeOverride; + + ALOGD ("%s: override seid=0x%X", fn, override_se ); + //activate every discovered secure element + for (int index=0; index < mActualNumEe; index++) + { + tNFA_EE_INFO& eeItem = mEeInfo[index]; + + if ((eeItem.ee_handle == EE_HANDLE_0xF3) || (eeItem.ee_handle == EE_HANDLE_0xF4)) + { + if (override_se && (override_se != eeItem.ee_handle) ) + continue; // do not enable all SEs; only the override one + + if (eeItem.ee_status != NFC_NFCEE_STATUS_INACTIVE) + { + ALOGD ("%s: h=0x%X already activated", fn, eeItem.ee_handle); + numActivatedEe++; + continue; + } + + { + SyncEventGuard guard (mEeSetModeEvent); + ALOGD ("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle); + if ((nfaStat = NFA_EeModeSet (eeItem.ee_handle, NFA_EE_MD_ACTIVATE)) == NFA_STATUS_OK) + { + mEeSetModeEvent.wait (); //wait for NFA_EE_MODE_SET_EVT + if (eeItem.ee_status == NFC_NFCEE_STATUS_ACTIVE) + numActivatedEe++; + } + else + ALOGE ("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat); + } + } + } //for + + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[xx].ee_status != NFC_NFCEE_STATUS_INACTIVE)) + { + mActiveEeHandle = mEeInfo[xx].ee_handle; + break; + } + } + + ALOGD ("%s: exit; ok=%u", fn, numActivatedEe > 0); + return numActivatedEe > 0; +} + + +/******************************************************************************* +** +** Function: deactivate +** +** Description: Turn off the secure element. +** seID: ID of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::deactivate (jint seID) +{ + static const char fn [] = "SecureElement::deactivate"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + int numDeactivatedEe = 0; + bool retval = false; + + ALOGD ("%s: enter; seID=0x%X, mActiveEeHandle=0x%X", fn, seID, mActiveEeHandle); + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + goto TheEnd; + } + + //if the controller is routing to sec elems or piping, + //then the secure element cannot be deactivated + if ((mCurrentRouteSelection == SecElemRoute) || mIsPiping) + { + ALOGE ("%s: still busy", fn); + goto TheEnd; + } + + if (mActiveEeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid EE handle", fn); + goto TheEnd; + } + + mActiveEeHandle = NFA_HANDLE_INVALID; + retval = true; + +TheEnd: + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: notifyTransactionListenersOfAid +** +** Description: Notify the NFC service about a transaction event from secure element. +** aid: Buffer contains application ID. +** aidLen: Length of application ID. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::notifyTransactionListenersOfAid (const UINT8* aidBuffer, UINT8 aidBufferLen) +{ + static const char fn [] = "SecureElement::notifyTransactionListenersOfAid"; + ALOGD ("%s: enter; aid len=%u", fn, aidBufferLen); + + if (aidBufferLen == 0) + return; + + jobject tlvJavaArray = NULL; + JNIEnv* e = NULL; + UINT8* tlv = 0; + const UINT16 tlvMaxLen = aidBufferLen + 10; + UINT16 tlvActualLen = 0; + bool stat = false; + + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + tlv = new UINT8 [tlvMaxLen]; + if (tlv == NULL) + { + ALOGE ("%s: fail allocate tlv", fn); + goto TheEnd; + } + + memcpy (tlv, aidBuffer, aidBufferLen); + tlvActualLen = aidBufferLen; + + tlvJavaArray = e->NewByteArray (tlvActualLen); + if (tlvJavaArray == NULL) + { + ALOGE ("%s: fail allocate array", fn); + goto TheEnd; + } + + e->SetByteArrayRegion ((jbyteArray)tlvJavaArray, 0, tlvActualLen, (jbyte *)tlv); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail fill array", fn); + goto TheEnd; + } + + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + goto TheEnd; + } + +TheEnd: + if (tlvJavaArray) + e->DeleteLocalRef (tlvJavaArray); + mNativeData->vm->DetachCurrentThread (); + delete [] tlv; + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: connectEE +** +** Description: Connect to the execution environment. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::connectEE () +{ + static const char fn [] = "SecureElement::connectEE"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retVal = false; + UINT8 destHost = 0; + unsigned long num = 0; + char pipeConfName[40]; + tNFA_HANDLE eeHandle = mActiveEeHandle; + + ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d", + fn, mActiveEeHandle, gSEId, gGatePipe, gUseStaticPipe); + + if (!mIsInit) + { + ALOGE ("%s: not init", fn); + return (false); + } + + if (gSEId != -1) + { + eeHandle = gSEId | NFA_HANDLE_GROUP_EE; + ALOGD ("%s: Using SEID: 0x%x", fn, eeHandle ); + } + + if (eeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid handle 0x%X", fn, eeHandle); + return (false); + } + + tNFA_EE_INFO *pEE = findEeByHandle (eeHandle); + + if (pEE == NULL) + { + ALOGE ("%s: Handle 0x%04x NOT FOUND !!", fn, eeHandle); + return (false); + } + + mNewSourceGate = 0; + + if (gGatePipe == -1) + { + // pipe/gate num was not specifed by app, get from config file + mNewPipeId = 0; + + // Construct the PIPE name based on the EE handle (e.g. NFA_HCI_STATIC_PIPE_ID_F3 for UICC0). + snprintf (pipeConfName, sizeof(pipeConfName), "NFA_HCI_STATIC_PIPE_ID_%02X", eeHandle & NFA_HANDLE_MASK); + + if (GetNumValue(pipeConfName, &num, sizeof(num)) && (num != 0)) + { + mNewPipeId = num; + ALOGD ("%s: Using static pipe id: 0x%X", __FUNCTION__, mNewPipeId); + } + else + { + ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName); + } + } + else + { + if (gUseStaticPipe) + { + mNewPipeId = gGatePipe; + } + else + { + mNewPipeId = 0; + mDestinationGate= gGatePipe; + } + } + + // If the .conf file had a static pipe to use, just use it. + if (mNewPipeId != 0) + { + nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, mNewPipeId); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail create static pipe; error=0x%X", fn, nfaStat); + retVal = false; + goto TheEnd; + } + } + else + { + if ( (pEE->num_tlvs >= 1) && (pEE->ee_tlv[0].tag == NFA_EE_TAG_HCI_HOST_ID) ) + destHost = pEE->ee_tlv[0].info[0]; + else + destHost = 2; + + // Get a list of existing gates and pipes + { + ALOGD ("%s: get gate, pipe list", fn); + SyncEventGuard guard (mPipeListEvent); + nfaStat = NFA_HciGetGateAndPipeList (mNfaHciHandle); + if (nfaStat == NFA_STATUS_OK) + { + mPipeListEvent.wait(); + if (mHciCfg.status == NFA_STATUS_OK) + { + for (UINT8 xx = 0; xx < mHciCfg.num_pipes; xx++) + { + if ( (mHciCfg.pipe[xx].dest_host == destHost) + && (mHciCfg.pipe[xx].dest_gate == mDestinationGate) ) + { + mNewSourceGate = mHciCfg.pipe[xx].local_gate; + mNewPipeId = mHciCfg.pipe[xx].pipe_id; + + ALOGD ("%s: found configured gate: 0x%02x pipe: 0x%02x", fn, mNewSourceGate, mNewPipeId); + break; + } + } + } + } + } + + if (mNewSourceGate == 0) + { + ALOGD ("%s: allocate gate", fn); + //allocate a source gate and store in mNewSourceGate + SyncEventGuard guard (mAllocateGateEvent); + if ((nfaStat = NFA_HciAllocGate (mNfaHciHandle)) != NFA_STATUS_OK) + { + ALOGE ("%s: fail allocate source gate; error=0x%X", fn, nfaStat); + goto TheEnd; + } + mAllocateGateEvent.wait (); + if (mCommandStatus != NFA_STATUS_OK) + goto TheEnd; + } + + if (mNewPipeId == 0) + { + ALOGD ("%s: create pipe", fn); + SyncEventGuard guard (mCreatePipeEvent); + nfaStat = NFA_HciCreatePipe (mNfaHciHandle, mNewSourceGate, destHost, mDestinationGate); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail create pipe; error=0x%X", fn, nfaStat); + goto TheEnd; + } + mCreatePipeEvent.wait (); + if (mCommandStatus != NFA_STATUS_OK) + goto TheEnd; + } + + { + ALOGD ("%s: open pipe", fn); + SyncEventGuard guard (mPipeOpenedEvent); + nfaStat = NFA_HciOpenPipe (mNfaHciHandle, mNewPipeId); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail open pipe; error=0x%X", fn, nfaStat); + goto TheEnd; + } + mPipeOpenedEvent.wait (); + if (mCommandStatus != NFA_STATUS_OK) + goto TheEnd; + } + } + + retVal = true; + +TheEnd: + mIsPiping = retVal; + if (!retVal) + { + // if open failed we need to de-allocate the gate + disconnectEE(0); + } + + ALOGD ("%s: exit; ok=%u", fn, retVal); + return retVal; +} + + +/******************************************************************************* +** +** Function: disconnectEE +** +** Description: Disconnect from the execution environment. +** seID: ID of secure element. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::disconnectEE (jint seID) +{ + static const char fn [] = "SecureElement::disconnectEE"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + tNFA_HANDLE eeHandle = seID; + + ALOGD("%s: seID=0x%X; handle=0x%04x", fn, seID, eeHandle); + + if (mNewSourceGate) + { + SyncEventGuard guard (mDeallocateGateEvent); + if ((nfaStat = NFA_HciDeallocGate (mNfaHciHandle, mNewSourceGate)) == NFA_STATUS_OK) + mDeallocateGateEvent.wait (); + else + ALOGE ("%s: fail dealloc gate; error=0x%X", fn, nfaStat); + } + mIsPiping = false; + return true; +} + + +/******************************************************************************* +** +** Function: transceive +** +** Description: Send data to the secure element; read it's response. +** xmitBuffer: Data to transmit. +** xmitBufferSize: Length of data. +** recvBuffer: Buffer to receive response. +** recvBufferMaxSize: Maximum size of buffer. +** recvBufferActualSize: Actual length of response. +** timeoutMillisec: timeout in millisecond. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer, + INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec) +{ + static const char fn [] = "SecureElement::transceive"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool isSuccess = false; + bool waitOk = false; + + ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%d", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); + + { + SyncEventGuard guard (mTransceiveEvent); + mTransDataSize = 0; + if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71)) + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer); + else + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer); + + if (nfaStat == NFA_STATUS_OK) + { + waitOk = mTransceiveEvent.wait (timeoutMillisec); + if (waitOk == false) //timeout occurs + { + ALOGE ("%s: wait response timeout", fn); + goto TheEnd; + } + } + else + { + ALOGE ("%s: fail send data; error=0x%X", fn, nfaStat); + goto TheEnd; + } + } + + if (mTransDataSize > recvBufferMaxSize) + recvBufferActualSize = recvBufferMaxSize; + else + recvBufferActualSize = mTransDataSize; + + memcpy(recvBuffer, mTransData, recvBufferActualSize); + isSuccess = true; + +TheEnd: + ALOGD ("%s: exit; isSuccess: %d; recvBufferActualSize: %ld", fn, isSuccess, recvBufferActualSize); + return (isSuccess); +} + + +/******************************************************************************* +** +** Function: notifyRfFieldEvent +** +** Description: Notify the NFC service about RF field events from the stack. +** isActive: Whether any secure element is activated. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::notifyRfFieldEvent (bool isActive) +{ + static const char fn [] = "SecureElement::notifyRfFieldEvent"; + JNIEnv *e = NULL; + + ALOGD ("%s: enter; is active=%u", fn, isActive); + mNativeData->vm->AttachCurrentThread (&e, NULL); + + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + if (isActive) + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldActivated); + else + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldDeactivated); + + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: storeUiccInfo +** +** Description: Store a copy of the execution environment information from the stack. +** info: execution environment information. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info) +{ + static const char fn [] = "SecureElement::storeUiccInfo"; + ALOGD ("%s: Status: %u Num EE: %u", fn, info.status, info.num_ee); + + SyncEventGuard guard (mUiccInfoEvent); + memcpy (&mUiccInfo, &info, sizeof(mUiccInfo)); + for (UINT8 xx = 0; xx < info.num_ee; xx++) + { + //for each technology (A, B, F, B'), print the bit field that shows + //what protocol(s) is support by that technology + ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x", + fn, xx, info.ee_disc_info[xx].ee_handle, + info.ee_disc_info[xx].la_protocol, + info.ee_disc_info[xx].lb_protocol, + info.ee_disc_info[xx].lf_protocol, + info.ee_disc_info[xx].lbp_protocol); + } + mUiccInfoEvent.notifyOne (); +} + + +/******************************************************************************* +** +** Function: getUiccId +** +** Description: Get the ID of the secure element. +** eeHandle: Handle to the secure element. +** uid: Array to receive the ID. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid) +{ + static const char fn [] = "SecureElement::getUiccId"; + ALOGD ("%s: ee h=0x%X", fn, eeHandle); + bool retval = false; + JNIEnv* e = NULL; + + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return false; + } + + findUiccByHandle (eeHandle); + //cannot get UID from the stack; nothing to do + +TheEnd: + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit; ret=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: getTechnologyList +** +** Description: Get all the technologies supported by a secure element. +** eeHandle: Handle of secure element. +** techList: List to receive the technologies. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList) +{ + static const char fn [] = "SecureElement::getTechnologyList"; + ALOGD ("%s: ee h=0x%X", fn, eeHandle); + bool retval = false; + JNIEnv* e = NULL; + jint theList = 0; + + mNativeData->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return false; + } + + tNFA_EE_DISCOVER_INFO *pUICC = findUiccByHandle (eeHandle); + + if (pUICC->la_protocol != 0) + theList = TARGET_TYPE_ISO14443_3A; + else if (pUICC->lb_protocol != 0) + theList = TARGET_TYPE_ISO14443_3B; + else if (pUICC->lf_protocol != 0) + theList = TARGET_TYPE_FELICA; + else if (pUICC->lbp_protocol != 0) + theList = TARGET_TYPE_ISO14443_3B; + else + theList = TARGET_TYPE_UNKNOWN; + +TheEnd: + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit; ret=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: adjustRoutes +** +** Description: Adjust routes in the controller's listen-mode routing table. +** selection: which set of routes to configure the controller. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::adjustRoutes (RouteSelection selection) +{ + static const char fn [] = "SecureElement::adjustRoutes"; + ALOGD ("%s: enter; selection=%u", fn, selection); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + RouteDataSet::Database* db = mRouteDataSet.getDatabase (RouteDataSet::DefaultRouteDatabase); + + if (selection == SecElemRoute) + db = mRouteDataSet.getDatabase (RouteDataSet::SecElemRouteDatabase); + + mCurrentRouteSelection = selection; + adjustProtocolRoutes (db, selection); + adjustTechnologyRoutes (db, selection); + HostAidRouter::getInstance ().deleteAllRoutes (); //stop all AID routes to host + + if (db->empty()) + { + if (selection == DefaultRoute) + HostAidRouter::getInstance ().addPpseRoute (); + ALOGD ("%s: no route configuration", fn); + goto TheEnd; + } + + +TheEnd: + NFA_EeUpdateNow (); //apply new routes now + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: applyRoutes +** +** Description: Read route data from file and apply them again. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::applyRoutes () +{ + static const char fn [] = "SecureElement::applyRoutes"; + ALOGD ("%s: enter", fn); + if (mCurrentRouteSelection != NoRoute) + { + mRouteDataSet.import (); //read XML file + adjustRoutes (mCurrentRouteSelection); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: adjustProtocolRoutes +** +** Description: Adjust default routing based on protocol in NFC listen mode. +** isRouteToEe: Whether routing to EE (true) or host (false). +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection) +{ + static const char fn [] = "SecureElement::adjustProtocolRoutes"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + const tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_ISO_DEP; + + /////////////////////// + // delete route to host + /////////////////////// + { + ALOGD ("%s: delete route to host", fn); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat); + } + + /////////////////////// + // delete route to every sec elem + /////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // configure route for every discovered sec elem + ////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + //if sec elem is active + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power + tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off + tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power + + //for every route in XML, look for protocol route; + //collect every protocol according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForProtocol* route = NULL; + if (routeData->mRouteType != RouteData::ProtocolRoute) + continue; //skip other kinds of routing data + route = (RouteDataForProtocol*) (*iter); + if (route->mNfaEeHandle == mEeInfo[i].ee_handle) + { + if (route->mSwitchOn) + protocolsSwitchOn |= route->mProtocol; + if (route->mSwitchOff) + protocolsSwitchOff |= route->mProtocol; + if (route->mBatteryOff) + protocolsBatteryOff |= route->mProtocol; + } + } + + if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle, + protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } //if sec elem is active + } //for every discovered sec elem + + ////////////////////// + // configure route to host + ////////////////////// + { + tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power + tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off + tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power + + //for every route in XML, look for protocol route; + //collect every protocol according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForProtocol* route = NULL; + if (routeData->mRouteType != RouteData::ProtocolRoute) + continue; //skip other kinds of routing data + route = (RouteDataForProtocol*) (*iter); + if (route->mNfaEeHandle == NFA_EE_HANDLE_DH) + { + if (route->mSwitchOn) + protocolsSwitchOn |= route->mProtocol; + if (route->mSwitchOff) + protocolsSwitchOff |= route->mProtocol; + if (route->mBatteryOff) + protocolsBatteryOff |= route->mProtocol; + } + } + + if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH, + protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // if route database is empty, setup a default route + ////////////////////// + if (db->empty()) + { + tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH; + if (routeSelection == SecElemRoute) + eeHandle = getDefaultEeHandle (); + ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultProtoRouting (eeHandle, protoMask, 0, 0); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: adjustTechnologyRoutes +** +** Description: Adjust default routing based on technology in NFC listen mode. +** isRouteToEe: Whether routing to EE (true) or host (false). +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection) +{ + static const char fn [] = "SecureElement::adjustTechnologyRoutes"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + const tNFA_TECHNOLOGY_MASK techMask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B; + + /////////////////////// + // delete route to host + /////////////////////// + { + ALOGD ("%s: delete route to host", fn); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat); + } + + /////////////////////// + // delete route to every sec elem + /////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + if ((nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // configure route for every discovered sec elem + ////////////////////// + for (int i=0; i < mActualNumEe; i++) + { + //if sec elem is active + if ((mEeInfo[i].num_interface != 0) && + (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && + (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE)) + { + tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power + tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off + tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power + + //for every route in XML, look for tech route; + //collect every tech according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForTechnology* route = NULL; + if (routeData->mRouteType != RouteData::TechnologyRoute) + continue; //skip other kinds of routing data + route = (RouteDataForTechnology*) (*iter); + if (route->mNfaEeHandle == mEeInfo[i].ee_handle) + { + if (route->mSwitchOn) + techsSwitchOn |= route->mTechnology; + if (route->mSwitchOff) + techsSwitchOff |= route->mTechnology; + if (route->mBatteryOff) + techsBatteryOff |= route->mTechnology; + } + } + + if (techsSwitchOn | techsSwitchOff | techsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle, + techsSwitchOn, techsSwitchOff, techsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } //if sec elem is active + } //for every discovered sec elem + + ////////////////////// + // configure route to host + ////////////////////// + { + tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power + tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off + tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power + + //for every route in XML, look for protocol route; + //collect every protocol according to it's desired power mode + for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++) + { + RouteData* routeData = *iter; + RouteDataForTechnology * route = NULL; + if (routeData->mRouteType != RouteData::TechnologyRoute) + continue; //skip other kinds of routing data + route = (RouteDataForTechnology*) (*iter); + if (route->mNfaEeHandle == NFA_EE_HANDLE_DH) + { + if (route->mSwitchOn) + techsSwitchOn |= route->mTechnology; + if (route->mSwitchOff) + techsSwitchOff |= route->mTechnology; + if (route->mBatteryOff) + techsBatteryOff |= route->mTechnology; + } + } + + if (techsSwitchOn | techsSwitchOff | techsBatteryOff) + { + ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH, + techsSwitchOn, techsSwitchOff, techsBatteryOff); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + } + + ////////////////////// + // if route database is empty, setup a default route + ////////////////////// + if (db->empty()) + { + tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH; + if (routeSelection == SecElemRoute) + eeHandle = getDefaultEeHandle (); + ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle); + SyncEventGuard guard (mRoutingEvent); + nfaStat = NFA_EeSetDefaultTechRouting (eeHandle, techMask, 0, 0); + if (nfaStat == NFA_STATUS_OK) + mRoutingEvent.wait (); + else + ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaEeCallback +** +** Description: Receive execution environment-related events from stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData) +{ + static const char fn [] = "SecureElement::nfaEeCallback"; + + switch (event) + { + case NFA_EE_REGISTER_EVT: + { + SyncEventGuard guard (sSecElem.mEeRegisterEvent); + ALOGD ("%s: NFA_EE_REGISTER_EVT; status=%u", fn, eventData->ee_register); + sSecElem.mEeRegisterEvent.notifyOne(); + } + break; + + case NFA_EE_MODE_SET_EVT: + { + ALOGD ("%s: NFA_EE_MODE_SET_EVT; status: 0x%04X handle: 0x%04X mActiveEeHandle: 0x%04X", fn, + eventData->mode_set.status, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle); + + if (eventData->mode_set.status == NFA_STATUS_OK) + { + tNFA_EE_INFO *pEE = sSecElem.findEeByHandle (eventData->mode_set.ee_handle); + if (pEE) + { + pEE->ee_status ^= 1; + ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status); + } + else + ALOGE ("%s: NFA_EE_MODE_SET_EVT; EE: 0x%04x not found. mActiveEeHandle: 0x%04x", fn, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle); + } + SyncEventGuard guard (sSecElem.mEeSetModeEvent); + sSecElem.mEeSetModeEvent.notifyOne(); + } + break; + + case NFA_EE_SET_TECH_CFG_EVT: + { + ALOGD ("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, eventData->status); + SyncEventGuard guard (sSecElem.mRoutingEvent); + sSecElem.mRoutingEvent.notifyOne (); + } + break; + + case NFA_EE_SET_PROTO_CFG_EVT: + { + ALOGD ("%s: NFA_EE_SET_PROTO_CFG_EVT; status=0x%X", fn, eventData->status); + SyncEventGuard guard (sSecElem.mRoutingEvent); + sSecElem.mRoutingEvent.notifyOne (); + } + break; + + case NFA_EE_ACTION_EVT: + { + tNFA_EE_ACTION& action = eventData->action; + if (action.trigger == NFC_EE_TRIG_SELECT) + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=select (0x%X)", fn, action.ee_handle, action.trigger); + else if (action.trigger == NFC_EE_TRIG_APP_INIT) + { + tNFC_APP_INIT& app_init = action.param.app_init; + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=app-init (0x%X); aid len=%u; data len=%u", fn, + action.ee_handle, action.trigger, app_init.len_aid, app_init.len_data); + //if app-init operation is successful; + //app_init.data[] contains two bytes, which are the status codes of the event; + //app_init.data[] does not contain an APDU response; + //see EMV Contactless Specification for Payment Systems; Book B; Entry Point Specification; + //version 2.1; March 2011; section 3.3.3.5; + if ( (app_init.len_data > 1) && + (app_init.data[0] == 0x90) && + (app_init.data[1] == 0x00) ) + { + sSecElem.notifyTransactionListenersOfAid (app_init.aid, app_init.len_aid); + } + } + else if (action.trigger == NFC_EE_TRIG_RF_PROTOCOL) + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf protocol (0x%X)", fn, action.ee_handle, action.trigger); + else if (action.trigger == NFC_EE_TRIG_RF_TECHNOLOGY) + ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf tech (0x%X)", fn, action.ee_handle, action.trigger); + else + ALOGE ("%s: NFA_EE_ACTION_EVT; h=0x%X; unknown trigger (0x%X)", fn, action.ee_handle, action.trigger); + } + break; + + case NFA_EE_DISCOVER_REQ_EVT: + ALOGD ("%s: NFA_EE_DISCOVER_REQ_EVT; status=0x%X; num ee=%u", __FUNCTION__, + eventData->discover_req.status, eventData->discover_req.num_ee); + sSecElem.storeUiccInfo (eventData->discover_req); + break; + + case NFA_EE_NO_CB_ERR_EVT: + ALOGD ("%s: NFA_EE_NO_CB_ERR_EVT status=%u", fn, eventData->status); + break; + + case NFA_EE_ADD_AID_EVT: + { + ALOGD ("%s: NFA_EE_ADD_AID_EVT status=%u", fn, eventData->status); + SyncEventGuard guard (sSecElem.mAidAddRemoveEvent); + sSecElem.mAidAddRemoveEvent.notifyOne (); + } + break; + + case NFA_EE_REMOVE_AID_EVT: + { + ALOGD ("%s: NFA_EE_REMOVE_AID_EVT status=%u", fn, eventData->status); + SyncEventGuard guard (sSecElem.mAidAddRemoveEvent); + sSecElem.mAidAddRemoveEvent.notifyOne (); + } + break; + + case NFA_EE_NEW_EE_EVT: + { + ALOGD ("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn, + eventData->new_ee.ee_handle, eventData->new_ee.ee_status); + // Indicate there are new EE + sSecElem.mbNewEE = true; + } + break; + + default: + ALOGE ("%s: unknown event=%u ????", fn, event); + break; + } +} + +/******************************************************************************* +** +** Function getSeVerInfo +** +** Description Gets version information and id for a secure element. The +** seIndex parmeter is the zero based index of the secure +** element to get verion info for. The version infommation +** is returned as a string int the verInfo parameter. +** +** Returns ture on success, false on failure +** +*******************************************************************************/ +bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid) +{ + ALOGD("%s: enter, seIndex=%d", __FUNCTION__, seIndex); + + if (seIndex > (mActualNumEe-1)) + { + ALOGE("%s: invalid se index: %d, only %d SEs in system", __FUNCTION__, seIndex, mActualNumEe); + return false; + } + + *seid = mEeInfo[seIndex].ee_handle; + + if ((mEeInfo[seIndex].num_interface == 0) || (mEeInfo[seIndex].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + { + return false; + } + + strncpy(verInfo, "Version info not available", verInfoSz-1); + verInfo[verInfoSz-1] = '\0'; + + UINT8 pipe = (mEeInfo[seIndex].ee_handle == EE_HANDLE_0xF3) ? 0x70 : 0x71; + + tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, pipe); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: NFA_HciAddStaticPipe() failed, pipe = 0x%x, error=0x%X", __FUNCTION__, pipe, nfaStat); + return true; + } + + SyncEventGuard guard (mVerInfoEvent); + if (NFA_STATUS_OK == (nfaStat = NFA_HciGetRegistry (mNfaHciHandle, pipe, 0x02))) + { + if (false == mVerInfoEvent.wait(200)) + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + } + else + { + snprintf(verInfo, verInfoSz-1, "Oberthur OS S/N: 0x%02x%02x%02x", mVerInfo[0], mVerInfo[1], mVerInfo[2]); + verInfo[verInfoSz-1] = '\0'; + } + } + else + { + ALOGE ("%s: NFA_HciGetRegistry () failed: 0x%X", __FUNCTION__, nfaStat); + } + return true; +} + +/******************************************************************************* +** +** Function getActualNumEe +** +** Description Returns number of secure elements we know about. +** +** Returns Number of secure elements we know about. +** +*******************************************************************************/ +UINT8 SecureElement::getActualNumEe() +{ + return mActualNumEe; +} + +/******************************************************************************* +** +** Function: nfaHciCallback +** +** Description: Receive Host Controller Interface-related events from stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData) +{ + static const char fn [] = "SecureElement::nfaHciCallback"; + ALOGD ("%s: event=0x%X", fn, event); + + switch (event) + { + case NFA_HCI_REGISTER_EVT: + { + ALOGD ("%s: NFA_HCI_REGISTER_EVT; status=0x%X; handle=0x%X", fn, + eventData->hci_register.status, eventData->hci_register.hci_handle); + SyncEventGuard guard (sSecElem.mHciRegisterEvent); + sSecElem.mNfaHciHandle = eventData->hci_register.hci_handle; + sSecElem.mHciRegisterEvent.notifyOne(); + } + break; + + case NFA_HCI_ALLOCATE_GATE_EVT: + { + ALOGD ("%s: NFA_HCI_ALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, eventData->status, eventData->allocated.gate); + SyncEventGuard guard (sSecElem.mAllocateGateEvent); + sSecElem.mCommandStatus = eventData->status; + sSecElem.mNewSourceGate = (eventData->allocated.status == NFA_STATUS_OK) ? eventData->allocated.gate : 0; + sSecElem.mAllocateGateEvent.notifyOne(); + } + break; + + case NFA_HCI_DEALLOCATE_GATE_EVT: + { + tNFA_HCI_DEALLOCATE_GATE& deallocated = eventData->deallocated; + ALOGD ("%s: NFA_HCI_DEALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, deallocated.status, deallocated.gate); + SyncEventGuard guard (sSecElem.mDeallocateGateEvent); + sSecElem.mDeallocateGateEvent.notifyOne(); + } + break; + + case NFA_HCI_GET_GATE_PIPE_LIST_EVT: + { + ALOGD ("%s: NFA_HCI_GET_GATE_PIPE_LIST_EVT; status=0x%X; num_pipes: %u num_gates: %u", fn, + eventData->gates_pipes.status, eventData->gates_pipes.num_pipes, eventData->gates_pipes.num_gates); + SyncEventGuard guard (sSecElem.mPipeListEvent); + sSecElem.mCommandStatus = eventData->gates_pipes.status; + sSecElem.mHciCfg = eventData->gates_pipes; + sSecElem.mPipeListEvent.notifyOne(); + } + break; + + case NFA_HCI_CREATE_PIPE_EVT: + { + ALOGD ("%s: NFA_HCI_CREATE_PIPE_EVT; status=0x%X; pipe=0x%X; src gate=0x%X; dest host=0x%X; dest gate=0x%X", fn, + eventData->created.status, eventData->created.pipe, eventData->created.source_gate, eventData->created.dest_host, eventData->created.dest_gate); + SyncEventGuard guard (sSecElem.mCreatePipeEvent); + sSecElem.mCommandStatus = eventData->created.status; + sSecElem.mNewPipeId = eventData->created.pipe; + sSecElem.mCreatePipeEvent.notifyOne(); + } + break; + + case NFA_HCI_OPEN_PIPE_EVT: + { + ALOGD ("%s: NFA_HCI_OPEN_PIPE_EVT; status=0x%X; pipe=0x%X", fn, eventData->opened.status, eventData->opened.pipe); + SyncEventGuard guard (sSecElem.mPipeOpenedEvent); + sSecElem.mCommandStatus = eventData->opened.status; + sSecElem.mPipeOpenedEvent.notifyOne(); + } + break; + + case NFA_HCI_EVENT_SENT_EVT: + ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status); + break; + + case NFA_HCI_RSP_RCVD_EVT: + ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status:0x%X, pipe=0x%X, rsp_code:0x%X, rsp_len=%u", fn, + eventData->rsp_rcvd.status, eventData->rsp_rcvd.pipe, + eventData->rsp_rcvd.rsp_code, eventData->rsp_rcvd.rsp_len); + break; + + case NFA_HCI_GET_REG_RSP_EVT : + ALOGD ("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn, + eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len); + if (eventData->registry.data_len >= 19 && ((eventData->registry.pipe == STATIC_PIPE_0x70) || (eventData->registry.pipe == STATIC_PIPE_0x71))) + { + // Oberthur OS version is in bytes 16,17, and 18 + sSecElem.mVerInfo[0] = eventData->registry.reg_data[16]; + sSecElem.mVerInfo[1] = eventData->registry.reg_data[17]; + sSecElem.mVerInfo[2] = eventData->registry.reg_data[18]; + SyncEventGuard guard (sSecElem.mVerInfoEvent); + sSecElem.mVerInfoEvent.notifyOne (); + } + break; + + case NFA_HCI_EVENT_RCVD_EVT: + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X", fn, + eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe); + if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71)) + { + //ISO7816 APDU arrived from sec elem's static pipes + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; %u bytes from static pipe", fn, eventData->rcvd_evt.evt_len); + sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; + memcpy (sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); + SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mTransceiveEvent.notifyOne (); + break; + } + switch (eventData->rcvd_evt.evt_code) + { + case NFA_HCI_EVT_POST_DATA: + { + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA; len=%u", fn, eventData->rcvd_evt.evt_len); + sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; + memcpy(sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); + SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mTransceiveEvent.notifyOne (); + } + break; + + case NFA_HCI_EVT_HCI_END_OF_OPERATION: + break; + + case NFA_HCI_EVT_HOT_PLUG: + break; + + case NFA_HCI_EVT_CONNECTIVITY: + break; + + case NFA_HCI_EVT_TRANSACTION: + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn); + // If we got an AID, notify any listeners + if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) ) + sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2], eventData->rcvd_evt.p_evt_buf[1]); + break; + + case NFA_HCI_EVT_OPERATION_ENDED: + break; + + default: + ALOGE ("%s: NFA_HCI_EVENT_RCVD_EVT; unknown event 0x%X ????", fn, eventData->rcvd_evt.evt_code); + break; + } + break; //case NFA_HCI_EVENT_RCVD_EVT + + default: + ALOGE ("%s: unknown event code=0x%X ????", fn, event); + break; + } +} + + +/******************************************************************************* +** +** Function: findEeByHandle +** +** Description: Find information about an execution environment. +** eeHandle: Handle to execution environment. +** +** Returns: Information about an execution environment. +** +*******************************************************************************/ +tNFA_EE_INFO *SecureElement::findEeByHandle (tNFA_HANDLE eeHandle) +{ + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if (mEeInfo[xx].ee_handle == eeHandle) + return (&mEeInfo[xx]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: getDefaultEeHandle +** +** Description: Get the handle to the execution environment. +** +** Returns: Handle to the execution environment. +** +*******************************************************************************/ +tNFA_HANDLE SecureElement::getDefaultEeHandle () +{ + // Find the first EE that is not the HCI Access i/f. + for (UINT8 xx = 0; xx < mActualNumEe; xx++) + { + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) ) + return (mEeInfo[xx].ee_handle); + } + return NFA_HANDLE_INVALID; +} + + + /******************************************************************************* + ** + ** Function: findUiccByHandle + ** + ** Description: Find information about an execution environment. + ** eeHandle: Handle of the execution environment. + ** + ** Returns: Information about the execution environment. + ** + *******************************************************************************/ +tNFA_EE_DISCOVER_INFO *SecureElement::findUiccByHandle (tNFA_HANDLE eeHandle) +{ + for (UINT8 index = 0; index < mUiccInfo.num_ee; index++) + { + if (mUiccInfo.ee_disc_info[index].ee_handle == eeHandle) + { + return (&mUiccInfo.ee_disc_info[index]); + } + } + ALOGE ("SecureElement::findUiccByHandle: ee h=0x%4x not found", eeHandle); + return NULL; +} + + +/******************************************************************************* +** +** Function: eeStatusToString +** +** Description: Convert status code to status text. +** status: Status code +** +** Returns: None +** +*******************************************************************************/ +const char* SecureElement::eeStatusToString (UINT8 status) +{ + switch (status) + { + case NFC_NFCEE_STATUS_ACTIVE: + return("Connected/Active"); + case NFC_NFCEE_STATUS_INACTIVE: + return("Connected/Inactive"); + case NFC_NFCEE_STATUS_REMOVED: + return("Removed"); + } + return("?? Unknown ??"); +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Receive card-emulation related events from stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + switch (event) + { + case NFA_CE_UICC_LISTEN_CONFIGURED_EVT: + { + SyncEventGuard guard (mUiccListenEvent); + mUiccListenEvent.notifyOne (); + } + break; + } +} + + +/******************************************************************************* +** +** Function: routeToSecureElement +** +** Description: Adjust controller's listen-mode routing table so transactions +** are routed to the secure elements. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::routeToSecureElement () +{ + static const char fn [] = "SecureElement::routeToSecureElement"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + tNFA_TECHNOLOGY_MASK tech_mask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B; + bool retval = false; + + if (! mIsInit) + { + ALOGE ("%s: not init", fn); + return false; + } + + if (mCurrentRouteSelection == SecElemRoute) + { + ALOGE ("%s: already sec elem route", fn); + return true; + } + + if (mActiveEeHandle == NFA_HANDLE_INVALID) + { + ALOGE ("%s: invalid EE handle", fn); + return false; + } + + adjustRoutes (SecElemRoute); + + { + unsigned long num = 0; + if (GetNumValue("UICC_LISTEN_TECH_MASK", &num, sizeof(num))) + tech_mask = num; + ALOGD ("%s: start UICC listen; h=0x%X; tech mask=0x%X", fn, mActiveEeHandle, tech_mask); + SyncEventGuard guard (mUiccListenEvent); + nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, tech_mask); + if (nfaStat == NFA_STATUS_OK) + { + mUiccListenEvent.wait (); + retval = true; + } + else + ALOGE ("%s: fail to start UICC listen", fn); + } + + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: routeToDefault +** +** Description: Adjust controller's listen-mode routing table so transactions +** are routed to the default destination. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool SecureElement::routeToDefault () +{ + static const char fn [] = "SecureElement::routeToDefault"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + bool retval = false; + + if (! mIsInit) + { + ALOGE ("%s: not init", fn); + return false; + } + + if (mCurrentRouteSelection == DefaultRoute) + { + ALOGE ("%s: already default route", fn); + return true; + } + + { + ALOGD ("%s: stop UICC listen; EE h=0x%X", fn, mActiveEeHandle); + SyncEventGuard guard (mUiccListenEvent); + nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, 0); + if (nfaStat == NFA_STATUS_OK) + { + mUiccListenEvent.wait (); + retval = true; + } + else + ALOGE ("%s: fail to stop UICC listen", fn); + } + + adjustRoutes (DefaultRoute); + + ALOGD ("%s: exit; ok=%u", fn, retval); + return retval; +} + + +/******************************************************************************* +** +** Function: isBusy +** +** Description: Whether controller is routing listen-mode events to +** secure elements or a pipe is connected. +** +** Returns: True if either case is true. +** +*******************************************************************************/ +bool SecureElement::isBusy () +{ + bool retval = (mCurrentRouteSelection == SecElemRoute) || mIsPiping; + ALOGD ("SecureElement::isBusy: %u", retval); + return retval; +} + diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h new file mode 100755 index 0000000..3542ac7 --- /dev/null +++ b/nci/jni/SecureElement.h @@ -0,0 +1,560 @@ +/***************************************************************************** +** +** Name: SecureElement.h +** +** Description: Communicate with secure elements that are attached +** to the NFC controller. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "SyncEvent.h" +#include "DataQueue.h" +#include "NfcJniUtil.h" +#include "RouteDataSet.h" +extern "C" +{ + #include "nfa_brcm_api.h" + #include "nfa_ee_api.h" + #include "nfa_hci_api.h" + #include "nfa_hci_defs.h" + #include "nfa_ce_api.h" +} + +#define MAX_TRANS_RECV_SIZE 1024 + +class SecureElement +{ +public: + tNFA_HANDLE mActiveEeHandle; + + + /******************************************************************************* + ** + ** Function: getInstance + ** + ** Description: Get the SecureElement singleton object. + ** + ** Returns: SecureElement object. + ** + *******************************************************************************/ + static SecureElement& getInstance (); + + + /******************************************************************************* + ** + ** Function: initialize + ** + ** Description: Initialize all member variables. + ** native: Native data. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool initialize (nfc_jni_native_data* native); + + + /******************************************************************************* + ** + ** Function: finalize + ** + ** Description: Release all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + void finalize (); + + + /******************************************************************************* + ** + ** Function: getListOfEeHandles + ** + ** Description: Get the list of handles of all execution environments. + ** e: Java Virtual Machine. + ** + ** Returns: List of handles of all execution environments. + ** + *******************************************************************************/ + jintArray getListOfEeHandles (JNIEnv* e); + + + /******************************************************************************* + ** + ** Function: activate + ** + ** Description: Turn on the secure element. + ** seID: ID of secure element. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool activate (jint seID); + + + /******************************************************************************* + ** + ** Function: deactivate + ** + ** Description: Turn off the secure element. + ** seID: ID of secure element. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool deactivate (jint seID); + + + /******************************************************************************* + ** + ** Function: connectEE + ** + ** Description: Connect to the execution environment. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool connectEE (); + + + /******************************************************************************* + ** + ** Function: disconnectEE + ** + ** Description: Disconnect from the execution environment. + ** seID: ID of secure element. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool disconnectEE (jint seID); + + + /******************************************************************************* + ** + ** Function: transceive + ** + ** Description: Send data to the secure element; read it's response. + ** xmitBuffer: Data to transmit. + ** xmitBufferSize: Length of data. + ** recvBuffer: Buffer to receive response. + ** recvBufferMaxSize: Maximum size of buffer. + ** recvBufferActualSize: Actual length of response. + ** timeoutMillisec: timeout in millisecond + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer, + INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec); + + + /******************************************************************************* + ** + ** Function: notifyRfFieldEvent + ** + ** Description: Notify the NFC service about RF field events from the stack. + ** isActive: Whether any secure element is activated. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyRfFieldEvent (bool isActive); + + + /******************************************************************************* + ** + ** Function: storeUiccInfo + ** + ** Description: Store a copy of the execution environment information from the stack. + ** info: execution environment information. + ** + ** Returns: None + ** + *******************************************************************************/ + void storeUiccInfo (tNFA_EE_DISCOVER_REQ& info); + + + /******************************************************************************* + ** + ** Function: getUiccId + ** + ** Description: Get the ID of the secure element. + ** eeHandle: Handle to the secure element. + ** uid: Array to receive the ID. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid); + + + /******************************************************************************* + ** + ** Function: getTechnologyList + ** + ** Description: Get all the technologies supported by a secure element. + ** eeHandle: Handle of secure element. + ** techList: List to receive the technologies. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList); + + + /******************************************************************************* + ** + ** Function: notifyTransactionListenersOfAid + ** + ** Description: Notify the NFC service about a transaction event from secure element. + ** aid: Buffer contains application ID. + ** aidLen: Length of application ID. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyTransactionListenersOfAid (const UINT8* aid, UINT8 aidLen); + + + /******************************************************************************* + ** + ** Function: notifyTransactionListenersOfTlv + ** + ** Description: Notify the NFC service about a transaction event from secure element. + ** The type-length-value contains AID and parameter. + ** tlv: type-length-value encoded in Basic Encoding Rule. + ** tlvLen: Length tlv. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyTransactionListenersOfTlv (const UINT8* tlv, UINT8 tlvLen); + + + /******************************************************************************* + ** + ** Function: connectionEventHandler + ** + ** Description: Receive card-emulation related events from stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: applyRoutes + ** + ** Description: Read route data from XML and apply them again + ** to every secure element. + ** + ** Returns: None + ** + *******************************************************************************/ + void applyRoutes (); + + + /******************************************************************************* + ** + ** Function: setActiveSeOverride + ** + ** Description: Specify which secure element to turn on. + ** activeSeOverride: ID of secure element + ** + ** Returns: None + ** + *******************************************************************************/ + void setActiveSeOverride (UINT8 activeSeOverride); + + + /******************************************************************************* + ** + ** Function: routeToSecureElement + ** + ** Description: Adjust controller's listen-mode routing table so transactions + ** are routed to the secure elements as specified in route.xml. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool routeToSecureElement (); + + + /******************************************************************************* + ** + ** Function: routeToDefault + ** + ** Description: Adjust controller's listen-mode routing table so transactions + ** are routed to the default destination specified in route.xml. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool routeToDefault (); + + + /******************************************************************************* + ** + ** Function: isBusy + ** + ** Description: Whether NFC controller is routing listen-mode events or a pipe is connected. + ** + ** Returns: True if either case is true. + ** + *******************************************************************************/ + bool isBusy (); + + + /******************************************************************************* + ** + ** Function getActualNumEe + ** + ** Description Returns number of secure elements we know about. + ** + ** Returns Number of secure elements we know about. + ** + *******************************************************************************/ + UINT8 getActualNumEe(); + + + /******************************************************************************* + ** + ** Function getSeVerInfo + ** + ** Description Gets version information and id for a secure element. The + ** seIndex parmeter is the zero based index of the secure + ** element to get verion info for. The version infommation + ** is returned as a string int the verInfo parameter. + ** + ** Returns ture on success, false on failure + ** + *******************************************************************************/ + bool getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid); + + +private: + enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute}; + static const int MAX_NUM_EE = 5; //max number of EE's + static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe + static const UINT8 STATIC_PIPE_0x71 = 0x71; //Broadcom's proprietary static pipe + static const UINT8 EVT_SEND_DATA = 0x10; //see specification ETSI TS 102 622 v9.0.0 (Host Controller Interface); section 9.3.3.3 + static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0 + static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1 + static SecureElement sSecElem; + + UINT8 mDestinationGate; //destination gate of the UICC + tNFA_HANDLE mNfaHciHandle; //NFA handle to NFA's HCI component + nfc_jni_native_data* mNativeData; + bool mIsInit; // whether EE is initialized + UINT8 mActualNumEe; // actual number of EE's reported by the stack + UINT8 mNumEePresent; // actual number of usable EE's + bool mbNewEE; + UINT8 mNewPipeId; + UINT8 mNewSourceGate; + UINT16 mActiveSeOverride; // active "enable" seid, 0 means activate all SEs + tNFA_STATUS mCommandStatus; //completion status of the last command + bool mIsPiping; //is a pipe connected to the controller? + RouteSelection mCurrentRouteSelection; + int mTransDataSize; + tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe + tNFA_EE_DISCOVER_REQ mUiccInfo; + tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg; + SyncEvent mEeRegisterEvent; + SyncEvent mHciRegisterEvent; + SyncEvent mEeSetModeEvent; + SyncEvent mPipeListEvent; + SyncEvent mCreatePipeEvent; + SyncEvent mPipeOpenedEvent; + SyncEvent mAllocateGateEvent; + SyncEvent mDeallocateGateEvent; + SyncEvent mRoutingEvent; + SyncEvent mUiccInfoEvent; + SyncEvent mUiccListenEvent; + SyncEvent mAidAddRemoveEvent; + SyncEvent mTransceiveEvent; + SyncEvent mVerInfoEvent; + UINT8 mVerInfo [3]; + UINT8 mTransData [MAX_TRANS_RECV_SIZE]; + UINT8 mHciBufferForStack [MAX_TRANS_RECV_SIZE]; + RouteDataSet mRouteDataSet; //routing data + std::vector mUsedAids; //AID's that are used in current routes + + + /******************************************************************************* + ** + ** Function: SecureElement + ** + ** Description: Initialize member variables. + ** + ** Returns: None + ** + *******************************************************************************/ + SecureElement (); + + + /******************************************************************************* + ** + ** Function: ~SecureElement + ** + ** Description: Release all resources. + ** + ** Returns: None + ** + *******************************************************************************/ + ~SecureElement (); + + + /******************************************************************************* + ** + ** Function: nfaEeCallback + ** + ** Description: Receive execution environment-related events from stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: nfaHciCallback + ** + ** Description: Receive Host Controller Interface-related events from stack. + ** event: Event code. + ** eventData: Event data. + ** + ** Returns: None + ** + *******************************************************************************/ + static void nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData); + + + /******************************************************************************* + ** + ** Function: findEeByHandle + ** + ** Description: Find information about an execution environment. + ** eeHandle: Handle to execution environment. + ** + ** Returns: Information about an execution environment. + ** + *******************************************************************************/ + tNFA_EE_INFO *findEeByHandle (tNFA_HANDLE eeHandle); + + + /******************************************************************************* + ** + ** Function: findUiccByHandle + ** + ** Description: Find information about an execution environment. + ** eeHandle: Handle of the execution environment. + ** + ** Returns: Information about the execution environment. + ** + *******************************************************************************/ + tNFA_EE_DISCOVER_INFO *findUiccByHandle (tNFA_HANDLE eeHandle); + + + /******************************************************************************* + ** + ** Function: getDefaultEeHandle + ** + ** Description: Get the handle to the execution environment. + ** + ** Returns: Handle to the execution environment. + ** + *******************************************************************************/ + tNFA_HANDLE getDefaultEeHandle (); + + + /******************************************************************************* + ** + ** Function: adjustRoutes + ** + ** Description: Adjust routes in the controller's listen-mode routing table. + ** selection: which set of routes to configure the controller. + ** + ** Returns: None + ** + *******************************************************************************/ + void adjustRoutes (RouteSelection selection); + + + /******************************************************************************* + ** + ** Function: adjustProtocolRoutes + ** + ** Description: Adjust default routing based on protocol in NFC listen mode. + ** isRouteToEe: Whether routing to EE (true) or host (false). + ** + ** Returns: None + ** + *******************************************************************************/ + void adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection); + + + /******************************************************************************* + ** + ** Function: adjustTechnologyRoutes + ** + ** Description: Adjust default routing based on technology in NFC listen mode. + ** isRouteToEe: Whether routing to EE (true) or host (false). + ** + ** Returns: None + ** + *******************************************************************************/ + void adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection); + + + /******************************************************************************* + ** + ** Function: getEeInfo + ** + ** Description: Get latest information about execution environments from stack. + ** + ** Returns: True if at least 1 EE is available. + ** + *******************************************************************************/ + bool getEeInfo (); + + + /******************************************************************************* + ** + ** Function: eeStatusToString + ** + ** Description: Convert status code to status text. + ** status: Status code + ** + ** Returns: None + ** + *******************************************************************************/ + static const char* eeStatusToString (UINT8 status); + + + /******************************************************************************* + ** + ** Function: encodeAid + ** + ** Description: Encode AID in type-length-value using Basic Encoding Rule. + ** tlv: Buffer to store TLV. + ** tlvMaxLen: TLV buffer's maximum length. + ** tlvActualLen: TLV buffer's actual length. + ** aid: Buffer of Application ID. + ** aidLen: Aid buffer's actual length. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool encodeAid (UINT8* tlv, UINT16 tlvMaxLen, UINT16& tlvActualLen, const UINT8* aid, UINT8 aidLen); +}; + diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h new file mode 100644 index 0000000..5828569 --- /dev/null +++ b/nci/jni/SyncEvent.h @@ -0,0 +1,167 @@ +/***************************************************************************** +** +** Name: SyncEvent.h +** +** Description: Synchronize two or more threads using a condition variable +** and a mutex. +** +** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. +** Proprietary and confidential. +** +*****************************************************************************/ +#pragma once +#include "CondVar.h" +#include "Mutex.h" + + +class SyncEvent +{ +public: + /******************************************************************************* + ** + ** Function: ~SyncEvent + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~SyncEvent () + { + mMutex.unlock (); + } + + + /******************************************************************************* + ** + ** Function: start + ** + ** Description: Start a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void start () + { + mMutex.lock (); + } + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the thread and wait for the event to occur. + ** + ** Returns: None. + ** + *******************************************************************************/ + void wait () + { + mCondVar.wait (mMutex); + end (); + } + + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the thread and wait for the event to occur. + ** millisec: Timeout in milliseconds. + ** + ** Returns: True if wait is successful; false if timeout occurs. + ** + *******************************************************************************/ + bool wait (long millisec) + { + bool retVal = mCondVar.wait (mMutex, millisec); + end (); + return retVal; + } + + + /******************************************************************************* + ** + ** Function: notifyOne + ** + ** Description: Notify a blocked thread that the event has occured. Unblocks it. + ** + ** Returns: None. + ** + *******************************************************************************/ + void notifyOne () + { + mCondVar.notifyOne (); + end (); + } + + + /******************************************************************************* + ** + ** Function: end + ** + ** Description: End a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void end () + { + mMutex.unlock (); + } + +private: + CondVar mCondVar; + Mutex mMutex; +}; + + +/*****************************************************************************/ +/*****************************************************************************/ + + +/***************************************************************************** +** +** Name: SyncEventGuard +** +** Description: Automatically start and end a synchronization event. +** +*****************************************************************************/ +class SyncEventGuard +{ +public: + /******************************************************************************* + ** + ** Function: SyncEventGuard + ** + ** Description: Start a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + SyncEventGuard (SyncEvent& event) + : mEvent (event) + { + event.start (); //automatically start operation + }; + + + /******************************************************************************* + ** + ** Function: ~SyncEventGuard + ** + ** Description: End a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~SyncEventGuard () + { + mEvent.end (); //automatically end operation + }; + +private: + SyncEvent& mEvent; +}; + diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java new file mode 100755 index 0000000..db78496 --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpPacket; + +import java.io.IOException; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + */ +public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket { + + private int mHandle; + private int mSap; + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket() { } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + @Override + public int getLinkMiu(){ + return mLinkMiu; + } + + @Override + public int getSap(){ + return mSap; + } + + @Override + public void send(int sap, byte[] data) throws IOException { + if (!doSendTo(sap, data)) { + throw new IOException(); + } + } + + @Override + public LlcpPacket receive() throws IOException { + LlcpPacket packet = doReceiveFrom(mLinkMiu); + if (packet == null) { + throw new IOException(); + } + return packet; + } + + public int getHandle(){ + return mHandle; + } + + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java new file mode 100755 index 0000000..3a7e57f --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.DeviceHost.LlcpSocket; + +import java.io.IOException; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + */ +public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket { + private int mHandle; + private int mLocalMiu; + private int mLocalRw; + private int mLocalLinearBufferLength; + private int mSap; + private String mServiceName; + + public NativeLlcpServiceSocket(){ } + + private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength); + @Override + public LlcpSocket accept() throws IOException { + LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength); + if (socket == null) throw new IOException(); + return socket; + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java new file mode 100755 index 0000000..69506c5 --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; + +import java.io.IOException; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + */ +public class NativeLlcpSocket implements DeviceHost.LlcpSocket { + private int mHandle; + private int mSap; + private int mLocalMiu; + private int mLocalRw; + + public NativeLlcpSocket(){ } + + private native boolean doConnect(int nSap); + @Override + public void connectToSap(int sap) throws IOException { + if (!doConnect(sap)) { + throw new IOException(); + } + } + + private native boolean doConnectBy(String sn); + @Override + public void connectToService(String serviceName) throws IOException { + if (!doConnectBy(serviceName)) { + throw new IOException(); + } + } + + private native boolean doClose(); + @Override + public void close() throws IOException { + if (!doClose()) { + throw new IOException(); + } + } + + private native boolean doSend(byte[] data); + @Override + public void send(byte[] data) throws IOException { + if (!doSend(data)) { + throw new IOException(); + } + } + + private native int doReceive(byte[] recvBuff); + @Override + public int receive(byte[] recvBuff) throws IOException { + int receiveLength = doReceive(recvBuff); + if (receiveLength == -1) { + throw new IOException(); + } + return receiveLength; + } + + private native int doGetRemoteSocketMiu(); + @Override + public int getRemoteMiu() { return doGetRemoteSocketMiu(); } + + private native int doGetRemoteSocketRw(); + @Override + public int getRemoteRw() { return doGetRemoteSocketRw(); } + + @Override + public int getLocalSap(){ + return mSap; + } + + @Override + public int getLocalMiu(){ + return mLocalMiu; + } + + @Override + public int getLocalRw(){ + return mLocalRw; + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java new file mode 100755 index 0000000..57a8295 --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost; +import com.android.nfc.LlcpException; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.SharedPreferences; +import android.nfc.ErrorCodes; +import android.nfc.tech.Ndef; +import android.nfc.tech.TagTechnology; +import android.util.Log; + +import java.io.File; + +/** + * Native interface to the NFC Manager functions + */ +public class NativeNfcManager implements DeviceHost { + private static final String TAG = "NativeNfcManager"; + + private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; + + static final String PREF = "NxpDeviceHost"; + + private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; + private static final long FIRMWARE_MODTIME_DEFAULT = -1; + + static { + System.loadLibrary("nfc_nci_jni"); + } + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private final DeviceHostListener mListener; + private final Context mContext; + + public NativeNfcManager(Context context, DeviceHostListener listener) { + mListener = listener; + initializeNativeStructure(); + mContext = context; + } + + public static native boolean doSetScreenState(boolean state); + + public native boolean initializeNativeStructure(); + + private native boolean doDownload(); + + public native int doGetLastError(); + + @Override + public void checkFirmware() { + // Check that the NFC controller firmware is up to date. This + // ensures that firmware updates are applied in a timely fashion, + // and makes it much less likely that the user will have to wait + // for a firmware download when they enable NFC in the settings + // app. Firmware download can take some time, so this should be + // run in a separate thread. + + // check the timestamp of the firmware file + File firmwareFile; + int nbRetry = 0; + try { + firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); + } catch(NullPointerException npe) { + Log.e(TAG,"path to firmware file was null"); + return; + } + + long modtime = firmwareFile.lastModified(); + + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); + Log.d(TAG,"prev modtime: " + prev_fw_modtime); + Log.d(TAG,"new modtime: " + modtime); + if (prev_fw_modtime == modtime) { + return; + } + + // FW download. + while(nbRetry < 5) { + Log.d(TAG,"Perform Download"); + if(doDownload()) { + Log.d(TAG,"Download Success"); + // Now that we've finished updating the firmware, save the new modtime. + prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); + break; + } else { + Log.d(TAG,"Download Failed"); + nbRetry++; + } + } + } + + private native boolean doInitialize(); + + @Override + public boolean initialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) { + try { + Thread.sleep (12000); + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + } catch (InterruptedException e) { } + } + + return doInitialize(); + } + + private native boolean doDeinitialize(); + + @Override + public boolean deinitialize() { + SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false); + editor.apply(); + + return doDeinitialize(); + } + + @Override + public native void enableDiscovery(); + + @Override + public native void disableDiscovery(); + + @Override + public native int[] doGetSecureElementList(); + + @Override + public native void doSelectSecureElement(); + + @Override + public native void doDeselectSecureElement(); + + + private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, + String sn); + + @Override + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) + throws LlcpException { + LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + @Override + public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength) throws LlcpException { + LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + @Override + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, + int linearBufferLength) throws LlcpException { + LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + if (socket != null) { + return socket; + } else { + /* Get Error Status */ + int error = doGetLastError(); + + Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); + + switch (error) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + throw new LlcpException(error); + default: + throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); + } + } + } + + @Override + public native boolean doCheckLlcp(); + + @Override + public native boolean doActivateLlcp(); + + private native void doResetTimeouts(); + + @Override + public void resetTimeouts() { + doResetTimeouts(); + } + + @Override + public native void doAbort(); + + private native boolean doSetTimeout(int tech, int timeout); + @Override + public boolean setTimeout(int tech, int timeout) { + return doSetTimeout(tech, timeout); + } + + private native int doGetTimeout(int tech); + @Override + public int getTimeout(int tech) { + return doGetTimeout(tech); + } + + + @Override + public boolean canMakeReadOnly(int ndefType) { + return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2); + } + + @Override + public int getMaxTransceiveLength(int technology) { + switch (technology) { + case (TagTechnology.NFC_A): + case (TagTechnology.MIFARE_CLASSIC): + case (TagTechnology.MIFARE_ULTRALIGHT): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.NFC_B): + ///////////////////////////////////////////////////////////////// + // Broadcom: Since BCM2079x supports this, set NfcB max size. + //return 0; // PN544 does not support transceive of raw NfcB + return 253; // PN544 does not support transceive of raw NfcB + case (TagTechnology.NFC_V): + return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC + case (TagTechnology.ISO_DEP): + /* The maximum length of a normal IsoDep frame consists of: + * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes + * such a frame is supported. Extended length frames however + * are not supported. + */ + return 261; // Will be automatically split in two frames on the RF layer + case (TagTechnology.NFC_F): + return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC + default: + return 0; + } + + } + + private native void doSetP2pInitiatorModes(int modes); + @Override + public void setP2pInitiatorModes(int modes) { + doSetP2pInitiatorModes(modes); + } + + private native void doSetP2pTargetModes(int modes); + @Override + public void setP2pTargetModes(int modes) { + doSetP2pTargetModes(modes); + } + + public boolean getExtendedLengthApdusSupported() { + // TODO check BCM support + return false; + } + + public boolean enablePN544Quirks() { + return false; + } + + public byte[][] getWipeApdus() { + return null; + } + + private native String doDump(); + @Override + public String dump() { + return doDump(); + } + + /** + * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + mListener.onRemoteEndpointDiscovered(tag); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + mListener.onCardEmulationDeselected(); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + mListener.onCardEmulationAidSelected(aid); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + mListener.onLlcpLinkActivated(device); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { + mListener.onLlcpLinkDeactivated(device); + } + + private void notifySeFieldActivated() { + mListener.onRemoteFieldActivated(); + } + + private void notifySeFieldDeactivated() { + mListener.onRemoteFieldDeactivated(); + } + + private void notifySeApduReceived(byte[] apdu) { + mListener.onSeApduReceived(apdu); + } + + private void notifySeEmvCardRemoval() { + mListener.onSeEmvCardRemoval(); + } + + private void notifySeMifareAccess(byte[] block) { + mListener.onSeMifareAccess(block); + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java new file mode 100755 index 0000000..e2d91ec --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import android.content.Context; +import android.content.SharedPreferences; + + +/** + * Native interface to the NFC Secure Element functions + * + * {@hide} + */ +public class NativeNfcSecureElement { + + static final String PREF_SE_WIRED = "se_wired"; + + private final Context mContext; + + SharedPreferences mPrefs; + SharedPreferences.Editor mPrefsEditor; + + public NativeNfcSecureElement(Context context) { + mContext = context; + + mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE); + mPrefsEditor = mPrefs.edit(); + } + + private native int doNativeOpenSecureElementConnection(); + + public int doOpenSecureElementConnection() { + mPrefsEditor.putBoolean(PREF_SE_WIRED, true); + mPrefsEditor.apply(); + + return doNativeOpenSecureElementConnection(); + } + + private native boolean doNativeDisconnectSecureElementConnection(int handle); + + public boolean doDisconnect(int handle) { + mPrefsEditor.putBoolean(PREF_SE_WIRED, false); + mPrefsEditor.apply(); + + return doNativeDisconnectSecureElementConnection(handle); + } + + public native byte[] doTransceive(int handle, byte[] data); + + public native int[] doGetTechList(int handle); + + public native byte [] doGetUid(int handle); +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java new file mode 100755 index 0000000..eb8410f --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -0,0 +1,811 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.TagEndpoint; + +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.tech.IsoDep; +import android.nfc.tech.MifareClassic; +import android.nfc.tech.MifareUltralight; +import android.nfc.tech.Ndef; +import android.nfc.tech.NfcA; +import android.nfc.tech.NfcB; +import android.nfc.tech.NfcF; +import android.nfc.tech.NfcV; +import android.nfc.tech.TagTechnology; +import android.os.Bundle; +import android.util.Log; + +/** + * Native interface to the NFC tag functions + */ +public class NativeNfcTag implements TagEndpoint { + static final boolean DBG = true; + + static final int STATUS_CODE_TARGET_LOST = 146; + + private int[] mTechList; + private int[] mTechHandles; + private int[] mTechLibNfcTypes; + private Bundle[] mTechExtras; + private byte[][] mTechPollBytes; + private byte[][] mTechActBytes; + private byte[] mUid; + + // mConnectedHandle stores the *real* libnfc handle + // that we're connected to. + private int mConnectedHandle; + + // mConnectedTechIndex stores to which technology + // the upper layer stack is connected. Note that + // we may be connected to a libnfchandle without being + // connected to a technology - technology changes + // may occur runtime, whereas the underlying handle + // could stay present. Usually all technologies are on the + // same handle, with the exception of multi-protocol + // tags. + private int mConnectedTechIndex; // Index in mTechHandles + + private final String TAG = "NativeNfcTag"; + + private boolean mIsPresent; // Whether the tag is known to be still present + + private PresenceCheckWatchdog mWatchdog; + class PresenceCheckWatchdog extends Thread { + + private int watchdogTimeout = 125; + + private boolean isPresent = true; + private boolean isStopped = false; + private boolean isPaused = false; + private boolean doCheck = true; + + public synchronized void pause() { + isPaused = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void doResume() { + isPaused = false; + // We don't want to resume presence checking immediately, + // but go through at least one more wait period. + doCheck = false; + this.notifyAll(); + } + + public synchronized void end() { + isStopped = true; + doCheck = false; + this.notifyAll(); + } + + public synchronized void setTimeout(int timeout) { + watchdogTimeout = timeout; + doCheck = false; // Do it only after we have waited "timeout" ms again + this.notifyAll(); + } + + @Override + public synchronized void run() { + if (DBG) Log.d(TAG, "Starting background presence check"); + while (isPresent && !isStopped) { + try { + if (!isPaused) { + doCheck = true; + } + this.wait(watchdogTimeout); + if (doCheck) { + isPresent = doPresenceCheck(); + } else { + // 1) We are paused, waiting for unpause + // 2) We just unpaused, do pres check in next iteration + // (after watchdogTimeout ms sleep) + // 3) We just set the timeout, wait for this timeout + // to expire once first. + // 4) We just stopped, exit loop anyway + } + } catch (InterruptedException e) { + // Activity detected, loop + } + } + mIsPresent = false; + // Restart the polling loop + + Log.d(TAG, "Tag lost, restarting polling loop"); + doDisconnect(); + if (DBG) Log.d(TAG, "Stopping background presence check"); + } + } + + private native int doConnect(int handle); + public synchronized int connectWithStatus(int technology) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == technology) { + // Get the handle and connect, if not already connected + if (mConnectedHandle != mTechHandles[i]) { + // We're not yet connected to this handle, there are + // a few scenario's here: + // 1) We are not connected to anything yet - allow + // 2) We are connected to a technology which has + // a different handle (multi-protocol tag); we support + // switching to that. + if (mConnectedHandle == -1) { + // Not connected yet + //status = doConnect(mTechHandles[i]); + status = doConnect(i); + } else { + // Connect to a tech with a different handle + Log.d(TAG,"Connect to a tech with a different handle"); + //status = reconnectWithStatus(mTechHandles[i]); + status = reconnectWithStatus(i); + } + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + } else { + // 1) We are connected to a technology which has the same + // handle; we do not support connecting at a different + // level (libnfc auto-activates to the max level on + // any handle). + // 2) We are connecting to the ndef technology - always + // allowed. + if ((technology == TagTechnology.NDEF) || + (technology == TagTechnology.NDEF_FORMATABLE)) { + // special case for NDEF, this will cause switch to ISO_DEP frame intf + i = 0; + // status = 0; + } + status = reconnectWithStatus(i); + /* + if ((technology != TagTechnology.ISO_DEP) && + (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) { + // Don't allow to connect a -4 tag at a different level + // than IsoDep, as this is not supported by + // libNFC. + // revised for NFCA... do allow to connect a -4 tag at this level. + Log.d(TAG,"Connect to a tech with same different handle (rf intf change)"); + status = reconnectWithStatus(i); + if (status == 0) { + mConnectedHandle = mTechHandles[i]; + mConnectedTechIndex = i; + } + //status = 0; + } else { + status = 0; + } + */ + + + if (status == 0) { + mConnectedTechIndex = i; + // Handle was already identical + } + } + break; + } + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean connect(int technology) { + return connectWithStatus(technology) == 0; + } + + @Override + public synchronized void startPresenceChecking() { + // Once we start presence checking, we allow the upper layers + // to know the tag is in the field. + mIsPresent = true; + if (mWatchdog == null) { + mWatchdog = new PresenceCheckWatchdog(); + mWatchdog.start(); + } + } + + @Override + public synchronized boolean isPresent() { + // Returns whether the tag is still in the field to the best + // of our knowledge. + return mIsPresent; + } + native boolean doDisconnect(); + @Override + public synchronized boolean disconnect() { + boolean result = false; + + mIsPresent = false; + if (mWatchdog != null) { + // Watchdog has already disconnected or will do it + mWatchdog.end(); + try { + mWatchdog.join(); + } catch (InterruptedException e) { + // Should never happen. + } + mWatchdog = null; + result = true; + } else { + result = doDisconnect(); + } + + mConnectedTechIndex = -1; + mConnectedHandle = -1; + return result; + } + + native int doReconnect(); + public synchronized int reconnectWithStatus() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doReconnect(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean reconnect() { + return reconnectWithStatus() == 0; + } + + native int doHandleReconnect(int handle); + public synchronized int reconnectWithStatus(int handle) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doHandleReconnect(handle); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + + private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode); + @Override + public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doTransceive(data, raw, returnCode); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native int doCheckNdef(int[] ndefinfo); + private synchronized int checkNdefWithStatus(int[] ndefinfo) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + int status = doCheckNdef(ndefinfo); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return status; + } + @Override + public synchronized boolean checkNdef(int[] ndefinfo) { + return checkNdefWithStatus(ndefinfo) == 0; + } + + private native byte[] doRead(); + @Override + public synchronized byte[] readNdef() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + byte[] result = doRead(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + private native boolean doWrite(byte[] buf); + @Override + public synchronized boolean writeNdef(byte[] buf) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doWrite(buf); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doPresenceCheck(); + @Override + public synchronized boolean presenceCheck() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doPresenceCheck(); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doNdefFormat(byte[] key); + @Override + public synchronized boolean formatNdef(byte[] key) { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result = doNdefFormat(key); + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doMakeReadonly(byte[] key); + @Override + public synchronized boolean makeReadOnly() { + if (mWatchdog != null) { + mWatchdog.pause(); + } + boolean result; + if (hasTech(TagTechnology.MIFARE_CLASSIC)) { + result = doMakeReadonly(MifareClassic.KEY_DEFAULT); + } else { + // No key needed for other technologies + result = doMakeReadonly(new byte[] {}); + } + if (mWatchdog != null) { + mWatchdog.doResume(); + } + return result; + } + + native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act); + @Override + public synchronized boolean isNdefFormatable() { + // Let native code decide whether the currently activated tag + // is formatable. Although the name of the JNI function refers + // to ISO-DEP, the JNI function checks all tag types. + return doIsIsoDepNdefFormatable(mTechPollBytes[0], + mTechActBytes[0]); + } + + @Override + public int getHandle() { + // This is just a handle for the clients; it can simply use the first + // technology handle we have. + if (mTechHandles.length > 0) { + return mTechHandles[0]; + } else { + return 0; + } + } + + @Override + public byte[] getUid() { + return mUid; + } + + @Override + public int[] getTechList() { + return mTechList; + } + + private int getConnectedHandle() { + return mConnectedHandle; + } + + private int getConnectedLibNfcType() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) { + return mTechLibNfcTypes[mConnectedTechIndex]; + } else { + return 0; + } + } + + @Override + public int getConnectedTechnology() { + if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) { + return mTechList[mConnectedTechIndex]; + } else { + return 0; + } + } + native int doGetNdefType(int libnfctype, int javatype); + private int getNdefType(int libnfctype, int javatype) { + return doGetNdefType(libnfctype, javatype); + } + + private void addTechnology(int tech, int handle, int libnfctype) { + int[] mNewTechList = new int[mTechList.length + 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length); + mNewTechList[mTechList.length] = tech; + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length + 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length); + mNewHandleList[mTechHandles.length] = handle; + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length); + mNewTypeList[mTechLibNfcTypes.length] = libnfctype; + mTechLibNfcTypes = mNewTypeList; + } + + @Override + public void removeTechnology(int tech) { + synchronized (this) { + int techIndex = getTechIndex(tech); + if (techIndex != -1) { + int[] mNewTechList = new int[mTechList.length - 1]; + System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex); + System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex, + mTechList.length - techIndex - 1); + mTechList = mNewTechList; + + int[] mNewHandleList = new int[mTechHandles.length - 1]; + System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex); + System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex, + mTechHandles.length - techIndex - 1); + mTechHandles = mNewHandleList; + + int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1]; + System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex); + System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex, + mTechLibNfcTypes.length - techIndex - 1); + mTechLibNfcTypes = mNewTypeList; + + //The technology must be removed from the mTechExtras array, + //just like the above arrays. + //Remove the specified element from the array, + //then shift the remaining elements by one. + if (mTechExtras != null) + { + Bundle[] mNewTechExtras = new Bundle[mTechExtras.length - 1]; + System.arraycopy(mTechExtras, 0, mNewTechExtras, 0, techIndex); + System.arraycopy(mTechExtras, techIndex + 1, mNewTechExtras, techIndex, + mTechExtras.length - techIndex - 1); + mTechExtras = mNewTechExtras; + } + } + } + } + + public void addNdefFormatableTechnology(int handle, int libnfcType) { + synchronized (this) { + addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType); + } + } + + // This method exists to "patch in" the ndef technologies, + // which is done inside Java instead of the native JNI code. + // To not create some nasty dependencies on the order on which things + // are called (most notably getTechExtras()), it needs some additional + // checking. + public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType, + int javaType, int maxLength, int cardState) { + synchronized (this) { + addTechnology(TagTechnology.NDEF, handle, libnfcType); + + Bundle extras = new Bundle(); + extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg); + extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength); + extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState); + extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType)); + + if (mTechExtras == null) { + // This will build the tech extra's for the first time, + // including a NULL ref for the NDEF tech we generated above. + Bundle[] builtTechExtras = getTechExtras(); + builtTechExtras[builtTechExtras.length - 1] = extras; + } + else { + // Tech extras were built before, patch the NDEF one in + Bundle[] oldTechExtras = getTechExtras(); + Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1]; + System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length); + newTechExtras[oldTechExtras.length] = extras; + mTechExtras = newTechExtras; + } + + + } + } + + private int getTechIndex(int tech) { + int techIndex = -1; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + techIndex = i; + break; + } + } + return techIndex; + } + + private boolean hasTech(int tech) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech) { + hasTech = true; + break; + } + } + return hasTech; + } + + private boolean hasTechOnHandle(int tech, int handle) { + boolean hasTech = false; + for (int i = 0; i < mTechList.length; i++) { + if (mTechList[i] == tech && mTechHandles[i] == handle) { + hasTech = true; + break; + } + } + return hasTech; + + } + + private boolean isUltralightC() { + /* Make a best-effort attempt at classifying ULTRALIGHT + * vs ULTRALIGHT-C (based on NXP's public AN1303). + * The memory layout is as follows: + * Page # BYTE1 BYTE2 BYTE3 BYTE4 + * 2 INT1 INT2 LOCK LOCK + * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted) + * 4 DATA DATA DATA DATA (version info if factory-state) + * + * Read four blocks from page 2, which will get us both + * the lock page, the OTP page and the version info. + */ + boolean isUltralightC = false; + byte[] readCmd = { 0x30, 0x02 }; + int[] retCode = new int[2]; + byte[] respData = transceive(readCmd, false, retCode); + if (respData != null && respData.length == 16) { + // Check the lock bits (last 2 bytes in page2) + // and the OTP bytes (entire page 3) + if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 && + respData[5] == 0 && respData[6] == 0 && respData[7] == 0) { + // Very likely to be a blank card, look at version info + // in page 4. + if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) { + // This is Ultralight-C + isUltralightC = true; + } else { + // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight + // as a fallback if it's anything else + isUltralightC = false; + } + } else { + // See if we can find the NDEF CC in the OTP page and if it's + // smaller than major version two + if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) { + // OK, got NDEF. Technically we'd have to search for the + // NDEF TLV as well. However, this would add too much + // time for discovery and we can make already make a good guess + // with the data we have here. Byte 2 of the OTP page + // indicates the size of the tag - 0x06 is UL, anything + // above indicates UL-C. + if ((respData[6] & 0xff) > 0x06) { + isUltralightC = true; + } + } else { + // Fall back to ultralight + isUltralightC = false; + } + } + } + return isUltralightC; + } + + @Override + public Bundle[] getTechExtras() { + synchronized (this) { + if (mTechExtras != null) return mTechExtras; + mTechExtras = new Bundle[mTechList.length]; + for (int i = 0; i < mTechList.length; i++) { + Bundle extras = new Bundle(); + switch (mTechList[i]) { + case TagTechnology.NFC_A: { + byte[] actBytes = mTechActBytes[i]; + if ((actBytes != null) && (actBytes.length > 0)) { + extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF)); + } else { + // Unfortunately Jewel doesn't have act bytes, + // ignore this case. + } + extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]); + break; + } + + case TagTechnology.NFC_B: { + // What's returned from the PN544 is actually: + // 4 bytes app data + // 3 bytes prot info + byte[] appData = new byte[4]; + byte[] protInfo = new byte[3]; + if (mTechPollBytes[i].length >= 7) { + System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4); + System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3); + + extras.putByteArray(NfcB.EXTRA_APPDATA, appData); + extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo); + } + break; + } + + case TagTechnology.NFC_F: { + byte[] pmm = new byte[8]; + byte[] sc = new byte[2]; + if (mTechPollBytes[i].length >= 8) { + // At least pmm is present + System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8); + extras.putByteArray(NfcF.EXTRA_PMM, pmm); + } + if (mTechPollBytes[i].length == 10) { + System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2); + extras.putByteArray(NfcF.EXTRA_SC, sc); + } + break; + } + + case TagTechnology.ISO_DEP: { + if (hasTech(TagTechnology.NFC_A)) { + extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]); + } + else { + extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]); + } + break; + } + + case TagTechnology.NFC_V: { + // First byte response flags, second byte DSFID + if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) { + extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]); + extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]); + } + break; + } + + case TagTechnology.MIFARE_ULTRALIGHT: { + boolean isUlc = isUltralightC(); + extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc); + break; + } + + default: { + // Leave the entry in the array null + continue; + } + } + mTechExtras[i] = extras; + } + return mTechExtras; + } + } + + @Override + public NdefMessage findAndReadNdef() { + // Try to find NDEF on any of the technologies. + int[] technologies = getTechList(); + int[] handles = mTechHandles; + NdefMessage ndefMsg = null; + boolean foundFormattable = false; + int formattableHandle = 0; + int formattableLibNfcType = 0; + int status; + + for (int techIndex = 0; techIndex < technologies.length; techIndex++) { + // have we seen this handle before? + for (int i = 0; i < techIndex; i++) { + if (handles[i] == handles[techIndex]) { + continue; // don't check duplicate handles + } + } + + status = connectWithStatus(technologies[techIndex]); + if (status != 0) { + Log.d(TAG, "Connect Failed - status = "+ status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + // Check if this type is NDEF formatable + if (!foundFormattable) { + if (isNdefFormatable()) { + foundFormattable = true; + formattableHandle = getConnectedHandle(); + formattableLibNfcType = getConnectedLibNfcType(); + // We'll only add formattable tech if no ndef is + // found - this is because libNFC refuses to format + // an already NDEF formatted tag. + } + reconnect(); + } + + int[] ndefinfo = new int[2]; + status = checkNdefWithStatus(ndefinfo); + if (status != 0) { + Log.d(TAG, "Check NDEF Failed - status = " + status); + if (status == STATUS_CODE_TARGET_LOST) { + break; + } + continue; // try next handle + } + + // found our NDEF handle + boolean generateEmptyNdef = false; + + int supportedNdefLength = ndefinfo[0]; + int cardState = ndefinfo[1]; + byte[] buff = readNdef(); + if (buff != null) { + try { + ndefMsg = new NdefMessage(buff); + addNdefTechnology(ndefMsg, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } catch (FormatException e) { + // Create an intent anyway, without NDEF messages + generateEmptyNdef = true; + } + } else { + generateEmptyNdef = true; + } + + if (generateEmptyNdef) { + ndefMsg = null; + addNdefTechnology(null, + getConnectedHandle(), + getConnectedLibNfcType(), + getConnectedTechnology(), + supportedNdefLength, cardState); + reconnect(); + } + break; + } + + if (ndefMsg == null && foundFormattable) { + // Tag is not NDEF yet, and found a formattable target, + // so add formattable tech to tech list. + addNdefFormatableTechnology( + formattableHandle, + formattableLibNfcType); + } + + return ndefMsg; + } +} diff --git a/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java new file mode 100755 index 0000000..094f46a --- /dev/null +++ b/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.nfc.dhimpl; + +import com.android.nfc.DeviceHost.NfcDepEndpoint; + +/** + * Native interface to the P2P Initiator functions + */ +public class NativeP2pDevice implements NfcDepEndpoint { + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + private native byte[] doReceive(); + @Override + public byte[] receive() { + return doReceive(); + } + + private native boolean doSend(byte[] data); + @Override + public boolean send(byte[] data) { + return doSend(data); + } + + private native boolean doConnect(); + @Override + public boolean connect() { + return doConnect(); + } + + private native boolean doDisconnect(); + @Override + public boolean disconnect() { + return doDisconnect(); + } + + public native byte[] doTransceive(byte[] data); + @Override + public byte[] transceive(byte[] data) { + return doTransceive(data); + } + + @Override + public int getHandle() { + return mHandle; + } + + @Override + public int getMode() { + return mMode; + } + + @Override + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java index f969627..14544d2 100755 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -43,6 +43,20 @@ public class NativeNfcManager implements DeviceHost { private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; private static final long FIRMWARE_MODTIME_DEFAULT = -1; + //TODO: dont hardcode this + private static final byte[][] EE_WIPE_APDUS = { + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, + (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00}, + {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, + (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00}, + {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + }; + + static { System.loadLibrary("nfc_jni"); } @@ -310,6 +324,14 @@ public class NativeNfcManager implements DeviceHost { return false; } + public boolean enablePN544Quirks() { + return true; + } + + public byte[][] getWipeApdus() { + return EE_WIPE_APDUS; + } + private native String doDump(); @Override public String dump() { diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java index 047e3d5..a78a136 100644 --- a/src/com/android/nfc/DeviceHost.java +++ b/src/com/android/nfc/DeviceHost.java @@ -216,5 +216,9 @@ public interface DeviceHost { boolean getExtendedLengthApdusSupported(); + boolean enablePN544Quirks(); + + byte[][] getWipeApdus(); + String dump(); } diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 3e7a6b5..c42bdc0 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -101,8 +101,6 @@ public class NfcService extends Application implements DeviceHostListener { static final String PREF_FIRST_BOOT = "first_boot"; static final String PREF_AIRPLANE_OVERRIDE = "airplane_override"; - static final boolean PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE = true; - static final int MSG_NDEF_TAG = 0; static final int MSG_CARD_EMULATION = 1; static final int MSG_LLCP_LINK_ACTIVATION = 2; @@ -160,19 +158,6 @@ public class NfcService extends Application implements DeviceHostListener { public static final String EXTRA_MIFARE_BLOCK = "com.android.nfc_extras.extra.MIFARE_BLOCK"; - //TODO: dont hardcode this - private static final byte[][] EE_WIPE_APDUS = { - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, - (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00}, - {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, - (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00}, - {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00}, - {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, - }; - // NFC Execution Environment // fields below are protected by this private NativeNfcSecureElement mSecureElement; @@ -585,7 +570,12 @@ public class NfcService extends Application implements DeviceHostListener { void executeEeWipe() { // TODO: read SE reset list from /system/etc - byte[][]apdus = EE_WIPE_APDUS; + byte[][]apdus = mDeviceHost.getWipeApdus(); + + if (apdus == null) { + Log.d(TAG, "No wipe APDUs found"); + return; + } boolean tempEnable = mState == NfcAdapter.STATE_OFF; if (tempEnable) { @@ -1412,7 +1402,7 @@ public class NfcService extends Application implements DeviceHostListener { try { watchDog.start(); - if (PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE && mScreenState == SCREEN_STATE_OFF) { + if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) { /* TODO undo this after the LLCP stack is fixed. * Use a different sequence when turning the screen off to * workaround race conditions in pn544 libnfc. The race occurs -- cgit v1.1 From a0069c828b8e09089ce38fe80c058268a44fc932 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 30 Jul 2012 16:09:59 -0700 Subject: Follow-up NFC code drop. (DO NOT MERGE) From partner, uploaded 07/26/2012; modified to fit in new dhimpl/jni split. Change-Id: I3a8c04ab9427adc1295b7b46ec1308f98a2c2c5e --- nci/jni/NativeNfcManager.cpp | 44 +++++------ nci/jni/PeerToPeer.cpp | 88 ++++++++------------- nci/jni/PeerToPeer.h | 4 +- nci/jni/SecureElement.cpp | 89 +++++++++------------- nci/jni/SecureElement.h | 7 +- .../com/android/nfc/dhimpl/NativeNfcManager.java | 48 +----------- 6 files changed, 92 insertions(+), 188 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 0648852..d9be2e6 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -40,7 +40,7 @@ extern "C" extern UINT8 *p_nfa_dm_lptd_cfg; extern UINT8 *p_nfa_dm_start_up_cfg; extern const UINT8 nfca_version_string []; -extern "C" void nfa_app_post_nci_reset (); +extern "C" void nfa_app_post_nci_reset (UINT32 brcm_hw_id); namespace android { extern bool gIsTagDeactivating; @@ -513,28 +513,6 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) return JNI_FALSE; } - unsigned long num = 0; - - if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) - nat->tech_mask = num; - else - nat->tech_mask = DEFAULT_TECH_MASK; - - ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); - - // Always restore LPTD Configuration to the stack default. - if (sOriginalLptdCfg != NULL) - p_nfa_dm_lptd_cfg = sOriginalLptdCfg; - else - sOriginalLptdCfg = p_nfa_dm_lptd_cfg; - - // Override LPTD from the config file if it is found. - if (GetStrValue(NAME_LPTD_CFG, (char*)&sNewLptdCfg[0], sizeof(sNewLptdCfg))) - { - // Set stack pointer to use value. - p_nfa_dm_lptd_cfg = &sNewLptdCfg[0]; - } - PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); ALOGD ("%s: exit", __FUNCTION__); @@ -718,6 +696,23 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) ///////////////////////////////////////////////////////////////////////////////// // Add extra configuration here (work-arounds, etc.) + struct nfc_jni_native_data *nat = getNative(e, o); + + if ( nat ) + { + if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) + nat->tech_mask = num; + else + nat->tech_mask = DEFAULT_TECH_MASK; + + ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); + } + + // Always restore LPTD Configuration to the stack default. + if (sOriginalLptdCfg != NULL) + p_nfa_dm_lptd_cfg = sOriginalLptdCfg; + + // if this value is not set or set and non-zero, enable multi-technology responses. if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) NFA_SetMultiTechRsp(TRUE); @@ -1678,7 +1673,8 @@ bool nfcManager_isNfcActive() *******************************************************************************/ void nfaBrcmInitCallback (UINT32 brcm_hw_id) { - nfa_app_post_nci_reset (); + ALOGD ("%s: enter; brcm_hw_id=0x%X", __FUNCTION__, brcm_hw_id); + nfa_app_post_nci_reset (brcm_hw_id); } diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 4c02da2..d98aba5 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -58,9 +58,6 @@ PeerToPeer::PeerToPeer () memset (mClients, 0, sizeof(mClients)); if (GetNumValue ("APPL_TRACE_LEVEL", &num, sizeof (num))) mAppLogLevel = num; - - if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) - mP2pListenTechMask = num; } @@ -107,6 +104,11 @@ void PeerToPeer::initialize (long jniVersion) { ALOGD ("PeerToPeer::initialize"); mJniVersion = jniVersion; + + unsigned long num = 0; + + if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) + mP2pListenTechMask = num; } @@ -260,7 +262,7 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service if (sSnepServiceName.compare(serviceName) == 0) serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 - SyncEventGuard guard (pSrv->mListenEvent); + SyncEventGuard guard (pSrv->mRegServerEvent); stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); if (stat != NFA_STATUS_OK) { @@ -269,8 +271,8 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service return (false); } ALOGD ("%s: wait for listen-completion event", fn); - // Wait for NFA_P2P_LISTEN_EVT - pSrv->mListenEvent.wait (); + // Wait for NFA_P2P_REG_SERVER_EVT + pSrv->mRegServerEvent.wait (); if (pSrv->mNfaP2pServerHandle == NFA_HANDLE_INVALID) { @@ -566,7 +568,7 @@ bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) if ((pSrv = findServer (jniHandle)) == NULL) { - ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service handle: %u", fn, jniHandle); + ALOGE ("%s: unknown service handle: %u", fn, jniHandle); return (false); } @@ -1153,6 +1155,10 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff static const char fn [] = "PeerToPeer::receive"; ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); NfaConn *pConn = NULL; + tNFA_STATUS stat = NFA_STATUS_FAILED; + UINT32 actualDataLen2 = 0; + BOOLEAN isMoreData = TRUE; + bool retVal = false; if (jniHandle == mRcvFakeNppJniHandle) return (feedNppFromSnep(buffer, bufferLen, actualLen)); @@ -1165,28 +1171,24 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); - // Only wait for data if data queue is empty. - if (pConn->mInboundQ.isEmpty()) + while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) { - // And don't wait if we're disconnected. - if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + stat = NFA_P2pReadData (pConn->mNfaConnHandle, bufferLen, &actualDataLen2, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen2 > 0)) //received some data { - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); - SyncEventGuard guard (pConn->mReadEvent); - pConn->mReadEvent.wait(); + actualLen = (UINT16) actualDataLen2; + retVal = true; + break; } - - // If the connection was disconnected while we were blocked... - if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); { - ALOGD ("%s: already disconnected while waiting", fn); - return (false); + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.wait(); } - } + } //while - bool stat = pConn->mInboundQ.dequeue (buffer, bufferLen, actualLen); - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; client h=0x%X stat=%u actual len=%u", fn, pConn->mNfaConnHandle, stat, actualLen); - return stat; + ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen); + return retVal; } @@ -1520,19 +1522,19 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev switch (p2pEvent) { - case NFA_P2P_LISTEN_EVT: // NFA_P2pRegisterServer() has started to listen - ALOGD ("%s: NFA_P2P_LISTEN_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, - eventData->listen.server_handle, eventData->listen.server_sap, eventData->listen.service_name); + case NFA_P2P_REG_SERVER_EVT: // NFA_P2pRegisterServer() has started to listen + ALOGD ("%s: NFA_P2P_REG_SERVER_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, + eventData->reg_server.server_handle, eventData->reg_server.server_sap, eventData->reg_server.service_name); - if ((pSrv = sP2p.findServer(eventData->listen.service_name)) == NULL) + if ((pSrv = sP2p.findServer(eventData->reg_server.service_name)) == NULL) { - ALOGE ("%s: NFA_P2P_LISTEN_EVT for unknown service: %s", fn, eventData->listen.service_name); + ALOGE ("%s: NFA_P2P_REG_SERVER_EVT for unknown service: %s", fn, eventData->reg_server.service_name); } else { - SyncEventGuard guard (pSrv->mListenEvent); - pSrv->mNfaP2pServerHandle = eventData->listen.server_handle; - pSrv->mListenEvent.notifyOne(); //unblock registerServer() + SyncEventGuard guard (pSrv->mRegServerEvent); + pSrv->mNfaP2pServerHandle = eventData->reg_server.server_handle; + pSrv->mRegServerEvent.notifyOne(); //unblock registerServer() } break; @@ -1619,18 +1621,6 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev { ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, eventData->data.handle, eventData->data.remote_sap); - const int maxBufSize = 2 * 1024; - UINT8 buffer [maxBufSize]; - UINT32 actualDataLen = 0; - BOOLEAN isMoreData = TRUE; - while (isMoreData) - { - actualDataLen = 0; - isMoreData = FALSE; - tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); - if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) - pConn->mInboundQ.enqueue (buffer, actualDataLen); - } SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.notifyOne(); } @@ -1783,18 +1773,6 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev { ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, eventData->data.handle, eventData->data.remote_sap); - const int maxBufSize = 2 * 1024; - UINT8 buffer [maxBufSize]; - UINT32 actualDataLen = 0; - BOOLEAN isMoreData = TRUE; - while (isMoreData) - { - actualDataLen = 0; - isMoreData = FALSE; - tNFA_STATUS stat = NFA_P2pReadData (eventData->data.handle, maxBufSize, &actualDataLen, buffer, &isMoreData); - if ((stat == NFA_STATUS_OK) && (actualDataLen > 0)) - pConn->mInboundQ.enqueue (buffer, actualDataLen); - } SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.notifyOne(); } diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index 00ead7f..166a6ac 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -10,7 +10,6 @@ *****************************************************************************/ #pragma once #include "SyncEvent.h" -#include "DataQueue.h" #include "NfcJniUtil.h" #include extern "C" @@ -595,7 +594,6 @@ public: UINT8 mRecvWindow; UINT16 mRemoteMaxInfoUnit; UINT8 mRemoteRecvWindow; - DataQueue mInboundQ; // store inbound data SyncEvent mReadEvent; // event for reading SyncEvent mCongEvent; // event for congestion SyncEvent mDisconnectingEvent; // event for disconnecting @@ -626,7 +624,7 @@ class P2pServer public: tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server tBRCM_JNI_HANDLE mJniHandle; // JNI Handle - SyncEvent mListenEvent; // for NFA_P2pRegisterServer() + SyncEvent mRegServerEvent; // for NFA_P2pRegisterServer() SyncEvent mConnRequestEvent; // for accept() std::string mServiceName; NfaConn *mServerConn[MAX_NFA_CONNS_PER_SERVER]; diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index f518650..08de696 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -67,12 +67,12 @@ SecureElement::SecureElement () mCommandStatus (NFA_STATUS_OK), mIsPiping (false), mCurrentRouteSelection (NoRoute), - mTransDataSize(0) + mActualResponseSize(0) { memset (&mEeInfo, 0, sizeof(mEeInfo)); memset (&mUiccInfo, 0, sizeof(mUiccInfo)); memset (&mHciCfg, 0, sizeof(mHciCfg)); - memset (mTransData, 0, MAX_TRANS_RECV_SIZE); + memset (mResponseData, 0, sizeof(mResponseData)); } @@ -189,7 +189,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) SyncEventGuard guard (mHciRegisterEvent); - nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE, MAX_TRANS_RECV_SIZE, mHciBufferForStack); + nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); @@ -810,15 +810,16 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* bool isSuccess = false; bool waitOk = false; - ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%d", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); + ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); { SyncEventGuard guard (mTransceiveEvent); - mTransDataSize = 0; + mActualResponseSize = 0; + memset (mResponseData, 0, sizeof(mResponseData)); if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71)) - nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer); + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); else - nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer); + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); if (nfaStat == NFA_STATUS_OK) { @@ -836,12 +837,12 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* } } - if (mTransDataSize > recvBufferMaxSize) + if (mActualResponseSize > recvBufferMaxSize) recvBufferActualSize = recvBufferMaxSize; else - recvBufferActualSize = mTransDataSize; + recvBufferActualSize = mActualResponseSize; - memcpy(recvBuffer, mTransData, recvBufferActualSize); + memcpy (recvBuffer, mResponseData, recvBufferActualSize); isSuccess = true; TheEnd: @@ -1668,12 +1669,14 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status); break; - case NFA_HCI_RSP_RCVD_EVT: - ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status:0x%X, pipe=0x%X, rsp_code:0x%X, rsp_len=%u", fn, - eventData->rsp_rcvd.status, eventData->rsp_rcvd.pipe, - eventData->rsp_rcvd.rsp_code, eventData->rsp_rcvd.rsp_len); + case NFA_HCI_RSP_RCVD_EVT: //response received from secure element + { + tNFA_HCI_RSP_RCVD& rsp_rcvd = eventData->rsp_rcvd; + ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status: 0x%X; code: 0x%X; pipe: 0x%X; len: %u", fn, + rsp_rcvd.status, rsp_rcvd.rsp_code, rsp_rcvd.pipe, rsp_rcvd.rsp_len); + } break; - + case NFA_HCI_GET_REG_RSP_EVT : ALOGD ("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn, eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len); @@ -1689,54 +1692,30 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event break; case NFA_HCI_EVENT_RCVD_EVT: - ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X", fn, - eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe); - if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71)) - { - //ISO7816 APDU arrived from sec elem's static pipes - ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; %u bytes from static pipe", fn, eventData->rcvd_evt.evt_len); - sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; - memcpy (sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X; data len: %u", fn, + eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len); + if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71)) + { + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; data from static pipe", fn); SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len; sSecElem.mTransceiveEvent.notifyOne (); - break; - } - switch (eventData->rcvd_evt.evt_code) + } + else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_POST_DATA) + { + ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA", fn); + SyncEventGuard guard (sSecElem.mTransceiveEvent); + sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len; + sSecElem.mTransceiveEvent.notifyOne (); + } + else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_TRANSACTION) { - case NFA_HCI_EVT_POST_DATA: - { - ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA; len=%u", fn, eventData->rcvd_evt.evt_len); - sSecElem.mTransDataSize = (eventData->rcvd_evt.evt_len > MAX_TRANS_RECV_SIZE) ? MAX_TRANS_RECV_SIZE : eventData->rcvd_evt.evt_len; - memcpy(sSecElem.mTransData, eventData->rcvd_evt.p_evt_buf, sSecElem.mTransDataSize); - SyncEventGuard guard (sSecElem.mTransceiveEvent); - sSecElem.mTransceiveEvent.notifyOne (); - } - break; - - case NFA_HCI_EVT_HCI_END_OF_OPERATION: - break; - - case NFA_HCI_EVT_HOT_PLUG: - break; - - case NFA_HCI_EVT_CONNECTIVITY: - break; - - case NFA_HCI_EVT_TRANSACTION: ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn); // If we got an AID, notify any listeners if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) ) sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2], eventData->rcvd_evt.p_evt_buf[1]); - break; - - case NFA_HCI_EVT_OPERATION_ENDED: - break; - - default: - ALOGE ("%s: NFA_HCI_EVENT_RCVD_EVT; unknown event 0x%X ????", fn, eventData->rcvd_evt.evt_code); - break; } - break; //case NFA_HCI_EVENT_RCVD_EVT + break; default: ALOGE ("%s: unknown event code=0x%X ????", fn, event); diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index 3542ac7..8bfb8f5 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -23,7 +23,6 @@ extern "C" #include "nfa_ce_api.h" } -#define MAX_TRANS_RECV_SIZE 1024 class SecureElement { @@ -340,6 +339,7 @@ public: private: + static const unsigned int MAX_RESPONSE_SIZE = 1024; enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute}; static const int MAX_NUM_EE = 5; //max number of EE's static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe @@ -362,7 +362,7 @@ private: tNFA_STATUS mCommandStatus; //completion status of the last command bool mIsPiping; //is a pipe connected to the controller? RouteSelection mCurrentRouteSelection; - int mTransDataSize; + int mActualResponseSize; //number of bytes in the response received from secure element tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe tNFA_EE_DISCOVER_REQ mUiccInfo; tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg; @@ -381,8 +381,7 @@ private: SyncEvent mTransceiveEvent; SyncEvent mVerInfoEvent; UINT8 mVerInfo [3]; - UINT8 mTransData [MAX_TRANS_RECV_SIZE]; - UINT8 mHciBufferForStack [MAX_TRANS_RECV_SIZE]; + UINT8 mResponseData [MAX_RESPONSE_SIZE]; RouteDataSet mRouteDataSet; //routing data std::vector mUsedAids; //AID's that are used in current routes diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index 57a8295..f732cac 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -35,13 +35,7 @@ import java.io.File; */ public class NativeNfcManager implements DeviceHost { private static final String TAG = "NativeNfcManager"; - - private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; - - static final String PREF = "NxpDeviceHost"; - - private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; - private static final long FIRMWARE_MODTIME_DEFAULT = -1; + static final String PREF = "NciDeviceHost"; static { System.loadLibrary("nfc_nci_jni"); @@ -72,46 +66,6 @@ public class NativeNfcManager implements DeviceHost { @Override public void checkFirmware() { - // Check that the NFC controller firmware is up to date. This - // ensures that firmware updates are applied in a timely fashion, - // and makes it much less likely that the user will have to wait - // for a firmware download when they enable NFC in the settings - // app. Firmware download can take some time, so this should be - // run in a separate thread. - - // check the timestamp of the firmware file - File firmwareFile; - int nbRetry = 0; - try { - firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); - } catch(NullPointerException npe) { - Log.e(TAG,"path to firmware file was null"); - return; - } - - long modtime = firmwareFile.lastModified(); - - SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); - long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); - Log.d(TAG,"prev modtime: " + prev_fw_modtime); - Log.d(TAG,"new modtime: " + modtime); - if (prev_fw_modtime == modtime) { - return; - } - - // FW download. - while(nbRetry < 5) { - Log.d(TAG,"Perform Download"); - if(doDownload()) { - Log.d(TAG,"Download Success"); - // Now that we've finished updating the firmware, save the new modtime. - prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); - break; - } else { - Log.d(TAG,"Download Failed"); - nbRetry++; - } - } } private native boolean doInitialize(); -- cgit v1.1 From 11d1aed981ebedf675029326f2602c1b1bfaf62e Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 2 Aug 2012 09:28:34 -0700 Subject: Don't route PPSE AIDs to the host by default. (DO NOT MERGE) In our current model these AIDs should be handled by the EE. Because this routing also activates Nfc-B listen mode, it causes some Beam inter-op issues with PN544-based devices. Change-Id: I865bbf7cdd48a781410ad3742426fa9b05751c70 --- nci/jni/SecureElement.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 08de696..c3fb42f 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -1031,8 +1031,6 @@ void SecureElement::adjustRoutes (RouteSelection selection) if (db->empty()) { - if (selection == DefaultRoute) - HostAidRouter::getInstance ().addPpseRoute (); ALOGD ("%s: no route configuration", fn); goto TheEnd; } -- cgit v1.1 From e2dcb2a8904291a5ec521d86487ac84811c537ed Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 2 Aug 2012 09:28:34 -0700 Subject: Don't route PPSE AIDs to the host by default. In our current model these AIDs should be handled by the EE. Because this routing also activates Nfc-B listen mode, it causes some Beam inter-op issues with PN544-based devices. Change-Id: I865bbf7cdd48a781410ad3742426fa9b05751c70 --- nci/jni/SecureElement.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 08de696..c3fb42f 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -1031,8 +1031,6 @@ void SecureElement::adjustRoutes (RouteSelection selection) if (db->empty()) { - if (selection == DefaultRoute) - HostAidRouter::getInstance ().addPpseRoute (); ALOGD ("%s: no route configuration", fn); goto TheEnd; } -- cgit v1.1 From 80cd2d684ffec51b1a05f9ab1bc7eacff311ecef Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 2 Aug 2012 10:26:09 -0700 Subject: Fix race conditions in NdefPushServer. (DO NOT MERGE) Exposed by the new stack; need to take locks around mRunning and mLlcpServerSocket. Bug: 6922853 Change-Id: Ic8e3b90d1a1c9d77b27308e3f18bf8871843206f --- src/com/android/nfc/ndefpush/NdefPushServer.java | 67 +++++++++++++++++------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/com/android/nfc/ndefpush/NdefPushServer.java b/src/com/android/nfc/ndefpush/NdefPushServer.java index ca58a67..bf92c17 100755 --- a/src/com/android/nfc/ndefpush/NdefPushServer.java +++ b/src/com/android/nfc/ndefpush/NdefPushServer.java @@ -117,28 +117,49 @@ public class NdefPushServer { /** Server class, used to listen for incoming connection request */ class ServerThread extends Thread { + // Variables below synchronized on NdefPushServer.this boolean mRunning = true; LlcpServerSocket mServerSocket; @Override public void run() { - while (mRunning) { + boolean threadRunning; + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } + while (threadRunning) { if (DBG) Log.d(TAG, "about create LLCP service socket"); try { - mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME, - MIU, 1, 1024); + synchronized (NdefPushServer.this) { + mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME, + MIU, 1, 1024); + } if (mServerSocket == null) { if (DBG) Log.d(TAG, "failed to create LLCP service socket"); return; } if (DBG) Log.d(TAG, "created LLCP service socket"); - while (mRunning) { + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } + + while (threadRunning) { + LlcpServerSocket serverSocket; + synchronized (NdefPushServer.this) { + serverSocket = mServerSocket; + } + if (serverSocket == null) return; + if (DBG) Log.d(TAG, "about to accept"); - LlcpSocket communicationSocket = mServerSocket.accept(); + LlcpSocket communicationSocket = serverSocket.accept(); if (DBG) Log.d(TAG, "accept returned " + communicationSocket); if (communicationSocket != null) { new ConnectionThread(communicationSocket).start(); } + + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } } if (DBG) Log.d(TAG, "stop running"); } catch (LlcpException e) { @@ -146,28 +167,36 @@ public class NdefPushServer { } catch (IOException e) { Log.e(TAG, "IO error", e); } finally { - if (mServerSocket != null) { - if (DBG) Log.d(TAG, "about to close"); - try { - mServerSocket.close(); - } catch (IOException e) { - // ignore + synchronized (NdefPushServer.this) { + if (mServerSocket != null) { + if (DBG) Log.d(TAG, "about to close"); + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; } - mServerSocket = null; } } + + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } } } public void shutdown() { - mRunning = false; - if (mServerSocket != null) { - try { - mServerSocket.close(); - } catch (IOException e) { - // ignore + synchronized (NdefPushServer.this) { + mRunning = false; + if (mServerSocket != null) { + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; } - mServerSocket = null; } } } -- cgit v1.1 From 17c6967521cc31828dcf22bd7d8628dd126474f8 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 2 Aug 2012 10:26:09 -0700 Subject: Fix race conditions in NdefPushServer. Exposed by the new stack; need to take locks around mRunning and mLlcpServerSocket. Bug: 6922853 Change-Id: Ic8e3b90d1a1c9d77b27308e3f18bf8871843206f --- src/com/android/nfc/ndefpush/NdefPushServer.java | 67 +++++++++++++++++------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/com/android/nfc/ndefpush/NdefPushServer.java b/src/com/android/nfc/ndefpush/NdefPushServer.java index ca58a67..bf92c17 100755 --- a/src/com/android/nfc/ndefpush/NdefPushServer.java +++ b/src/com/android/nfc/ndefpush/NdefPushServer.java @@ -117,28 +117,49 @@ public class NdefPushServer { /** Server class, used to listen for incoming connection request */ class ServerThread extends Thread { + // Variables below synchronized on NdefPushServer.this boolean mRunning = true; LlcpServerSocket mServerSocket; @Override public void run() { - while (mRunning) { + boolean threadRunning; + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } + while (threadRunning) { if (DBG) Log.d(TAG, "about create LLCP service socket"); try { - mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME, - MIU, 1, 1024); + synchronized (NdefPushServer.this) { + mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME, + MIU, 1, 1024); + } if (mServerSocket == null) { if (DBG) Log.d(TAG, "failed to create LLCP service socket"); return; } if (DBG) Log.d(TAG, "created LLCP service socket"); - while (mRunning) { + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } + + while (threadRunning) { + LlcpServerSocket serverSocket; + synchronized (NdefPushServer.this) { + serverSocket = mServerSocket; + } + if (serverSocket == null) return; + if (DBG) Log.d(TAG, "about to accept"); - LlcpSocket communicationSocket = mServerSocket.accept(); + LlcpSocket communicationSocket = serverSocket.accept(); if (DBG) Log.d(TAG, "accept returned " + communicationSocket); if (communicationSocket != null) { new ConnectionThread(communicationSocket).start(); } + + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } } if (DBG) Log.d(TAG, "stop running"); } catch (LlcpException e) { @@ -146,28 +167,36 @@ public class NdefPushServer { } catch (IOException e) { Log.e(TAG, "IO error", e); } finally { - if (mServerSocket != null) { - if (DBG) Log.d(TAG, "about to close"); - try { - mServerSocket.close(); - } catch (IOException e) { - // ignore + synchronized (NdefPushServer.this) { + if (mServerSocket != null) { + if (DBG) Log.d(TAG, "about to close"); + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; } - mServerSocket = null; } } + + synchronized (NdefPushServer.this) { + threadRunning = mRunning; + } } } public void shutdown() { - mRunning = false; - if (mServerSocket != null) { - try { - mServerSocket.close(); - } catch (IOException e) { - // ignore + synchronized (NdefPushServer.this) { + mRunning = false; + if (mServerSocket != null) { + try { + mServerSocket.close(); + } catch (IOException e) { + // ignore + } + mServerSocket = null; } - mServerSocket = null; } } } -- cgit v1.1 From 618ed5a492c6474d3d5fd11d06febded71b0a7c2 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 6 Aug 2012 11:37:35 -0700 Subject: Dump NFC controller firmware version in the logs. (DO NOT MERGE) Change-Id: I0ff7c460b53f56d7b98e1e27838cfd4243a2b0a0 --- nci/jni/NativeNfcManager.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index d9be2e6..eeb74ce 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -106,6 +106,7 @@ static SyncEvent sNfaEnableEvent; //event for NFA_Enable() static SyncEvent sNfaDisableEvent; //event for NFA_Disable() static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling() static SyncEvent sNfaSetConfigEvent; // event for Set_Config.... +static SyncEvent sNfaBuildInfoEvent; static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; @@ -626,7 +627,17 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) case NFA_DM_PWR_MODE_CHANGE_EVT: PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData); break; - + case NFA_DM_FIRMWARE_BUILD_INFO_EVT: + { + tNFA_BRCM_FW_BUILD_INFO* bldInfo = + (tNFA_BRCM_FW_BUILD_INFO*) eventData->p_vs_evt_data; + if (bldInfo != NULL) { + ALOGD("BCM2079x NFC FW version %d.%d", bldInfo->patch.major_ver, + bldInfo->patch.minor_ver); + } + sNfaBuildInfoEvent.notifyOne(); + } + break; default: ALOGD ("%s: unhandled event", __FUNCTION__); break; @@ -666,7 +677,6 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) NFA_Init(); NFA_BrcmInit (nfaBrcmInitCallback); - stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); if (stat == NFA_STATUS_OK) { @@ -687,6 +697,14 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) //sIsNfaEnabled indicates whether stack started successfully if (sIsNfaEnabled) { + { + SyncEventGuard versionGuard (sNfaBuildInfoEvent); + stat = NFA_BrcmGetFirmwareBuildInfo(); + if (stat == NFA_STATUS_OK) { + sNfaBuildInfoEvent.wait(); + } + } + SecureElement::getInstance().initialize (getNative(e, o)); nativeNfcTag_registerNdefTypeHandler (); NfcTag::getInstance().initialize (getNative(e, o)); -- cgit v1.1 From 34075ee7fdded0b5ace697536efe54442d49609c Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 6 Aug 2012 11:37:35 -0700 Subject: Dump NFC controller firmware version in the logs. Change-Id: I0ff7c460b53f56d7b98e1e27838cfd4243a2b0a0 --- nci/jni/NativeNfcManager.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index d9be2e6..eeb74ce 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -106,6 +106,7 @@ static SyncEvent sNfaEnableEvent; //event for NFA_Enable() static SyncEvent sNfaDisableEvent; //event for NFA_Disable() static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling() static SyncEvent sNfaSetConfigEvent; // event for Set_Config.... +static SyncEvent sNfaBuildInfoEvent; static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; @@ -626,7 +627,17 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) case NFA_DM_PWR_MODE_CHANGE_EVT: PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData); break; - + case NFA_DM_FIRMWARE_BUILD_INFO_EVT: + { + tNFA_BRCM_FW_BUILD_INFO* bldInfo = + (tNFA_BRCM_FW_BUILD_INFO*) eventData->p_vs_evt_data; + if (bldInfo != NULL) { + ALOGD("BCM2079x NFC FW version %d.%d", bldInfo->patch.major_ver, + bldInfo->patch.minor_ver); + } + sNfaBuildInfoEvent.notifyOne(); + } + break; default: ALOGD ("%s: unhandled event", __FUNCTION__); break; @@ -666,7 +677,6 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) NFA_Init(); NFA_BrcmInit (nfaBrcmInitCallback); - stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); if (stat == NFA_STATUS_OK) { @@ -687,6 +697,14 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) //sIsNfaEnabled indicates whether stack started successfully if (sIsNfaEnabled) { + { + SyncEventGuard versionGuard (sNfaBuildInfoEvent); + stat = NFA_BrcmGetFirmwareBuildInfo(); + if (stat == NFA_STATUS_OK) { + sNfaBuildInfoEvent.wait(); + } + } + SecureElement::getInstance().initialize (getNative(e, o)); nativeNfcTag_registerNdefTypeHandler (); NfcTag::getInstance().initialize (getNative(e, o)); -- cgit v1.1 From bb65a8d87ee523c92ca1b5f57efe139bab3859fe Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 7 Aug 2012 10:49:21 -0700 Subject: Allow NfcB connects in NCI stack. PN544 did not support this - move the code checking for that into dh implementation. Change-Id: I4def57697bc81cf599421f1ffbfa85c0db72c458 --- nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 4 ++++ src/com/android/nfc/NfcService.java | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java index eddde94..45a59d2 100755 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -136,6 +136,10 @@ public class NativeNfcTag implements TagEndpoint { private native int doConnect(int handle); public synchronized int connectWithStatus(int technology) { + if (technology == TagTechnology.NFC_B) { + // Not supported by PN544 + return -1; + } if (mWatchdog != null) { mWatchdog.pause(); } diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index c42bdc0..ab294ea 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -860,10 +860,6 @@ public class NfcService extends Application implements DeviceHostListener { return ErrorCodes.ERROR_DISCONNECT; } - if (technology == TagTechnology.NFC_B) { - return ErrorCodes.ERROR_NOT_SUPPORTED; - } - // Note that on most tags, all technologies are behind a single // handle. This means that the connect at the lower levels // will do nothing, as the tag is already connected to that handle. -- cgit v1.1 From 8d6ea79dad7c25f592722faf47709e1b918d4c21 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 7 Aug 2012 13:05:31 -0700 Subject: Allow different default MIU / window sizes. The new NCI stack can deal with larger MIU and rw sizes, which give us better p2p throughput. Change-Id: I6600f28ddafe142b64ead2df896823bb8d242fc5 --- .../com/android/nfc/dhimpl/NativeNfcManager.java | 20 +++++++++++++++--- .../com/android/nfc/dhimpl/NativeNfcManager.java | 17 +++++++++++++++ src/com/android/nfc/DeviceHost.java | 4 ++++ src/com/android/nfc/NfcService.java | 4 +++- src/com/android/nfc/P2pLinkManager.java | 18 ++++++++++------ src/com/android/nfc/snep/SnepClient.java | 24 ++++++++++++++++++++-- src/com/android/nfc/snep/SnepServer.java | 22 ++++++++++++++++++-- 7 files changed, 95 insertions(+), 14 deletions(-) diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index f732cac..8e53ad1 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -28,8 +28,6 @@ import android.nfc.tech.Ndef; import android.nfc.tech.TagTechnology; import android.util.Log; -import java.io.File; - /** * Native interface to the NFC Manager functions */ @@ -37,6 +35,9 @@ public class NativeNfcManager implements DeviceHost { private static final String TAG = "NativeNfcManager"; static final String PREF = "NciDeviceHost"; + static final int DEFAULT_LLCP_MIU = 1980; + static final int DEFAULT_LLCP_RWSIZE = 2; + static { System.loadLibrary("nfc_nci_jni"); } @@ -262,20 +263,32 @@ public class NativeNfcManager implements DeviceHost { public void setP2pTargetModes(int modes) { doSetP2pTargetModes(modes); } - + @Override public boolean getExtendedLengthApdusSupported() { // TODO check BCM support return false; } + @Override public boolean enablePN544Quirks() { return false; } + @Override public byte[][] getWipeApdus() { return null; } + @Override + public int getDefaultLlcpMiu() { + return DEFAULT_LLCP_MIU; + } + + @Override + public int getDefaultLlcpRwSize() { + return DEFAULT_LLCP_RWSIZE; + } + private native String doDump(); @Override public String dump() { @@ -336,4 +349,5 @@ public class NativeNfcManager implements DeviceHost { private void notifySeMifareAccess(byte[] block) { mListener.onSeMifareAccess(block); } + } diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java index 14544d2..903cafa 100755 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -43,6 +43,9 @@ public class NativeNfcManager implements DeviceHost { private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; private static final long FIRMWARE_MODTIME_DEFAULT = -1; + static final int DEFAULT_LLCP_MIU = 128; + static final int DEFAULT_LLCP_RWSIZE = 1; + //TODO: dont hardcode this private static final byte[][] EE_WIPE_APDUS = { {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, @@ -319,19 +322,32 @@ public class NativeNfcManager implements DeviceHost { doSetP2pTargetModes(modes); } + @Override public boolean getExtendedLengthApdusSupported() { // Not supported on the PN544 return false; } + @Override public boolean enablePN544Quirks() { return true; } + @Override public byte[][] getWipeApdus() { return EE_WIPE_APDUS; } + @Override + public int getDefaultLlcpMiu() { + return DEFAULT_LLCP_MIU; + } + + @Override + public int getDefaultLlcpRwSize() { + return DEFAULT_LLCP_RWSIZE; + } + private native String doDump(); @Override public String dump() { @@ -392,4 +408,5 @@ public class NativeNfcManager implements DeviceHost { private void notifySeMifareAccess(byte[] block) { mListener.onSeMifareAccess(block); } + } diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java index a78a136..b7336ad 100644 --- a/src/com/android/nfc/DeviceHost.java +++ b/src/com/android/nfc/DeviceHost.java @@ -220,5 +220,9 @@ public interface DeviceHost { byte[][] getWipeApdus(); + int getDefaultLlcpMiu(); + + int getDefaultLlcpRwSize(); + String dump(); } diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index ab294ea..13f224b 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -303,7 +303,9 @@ public class NfcService extends Application implements DeviceHostListener { HandoverManager handoverManager = new HandoverManager(mContext); mNfcDispatcher = new NfcDispatcher(this, handoverManager); - mP2pLinkManager = new P2pLinkManager(mContext, handoverManager); + + mP2pLinkManager = new P2pLinkManager(mContext, handoverManager, + mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize()); mSecureElement = new NativeNfcSecureElement(mContext); mEeRoutingState = ROUTE_OFF; diff --git a/src/com/android/nfc/P2pLinkManager.java b/src/com/android/nfc/P2pLinkManager.java index 253ddaf..9b23f65 100755 --- a/src/com/android/nfc/P2pLinkManager.java +++ b/src/com/android/nfc/P2pLinkManager.java @@ -167,6 +167,9 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba final Handler mHandler; final HandoverManager mHandoverManager; + final int mDefaultMiu; + final int mDefaultRwSize; + // Locked on NdefP2pManager.this int mLinkState; int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE @@ -179,9 +182,10 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba SharedPreferences mPrefs; boolean mFirstBeam; - public P2pLinkManager(Context context, HandoverManager handoverManager) { + public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu, + int defaultRwSize) { mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); - mDefaultSnepServer = new SnepServer(mDefaultSnepCallback); + mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize); mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback); if (ECHOSERVER_ENABLED) { @@ -201,6 +205,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE); mFirstBeam = mPrefs.getBoolean(NfcService.PREF_FIRST_BEAM, true); mHandoverManager = handoverManager; + mDefaultMiu = defaultMiu; + mDefaultRwSize = defaultRwSize; } /** @@ -417,11 +423,11 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba long time = SystemClock.elapsedRealtime(); - try { if (DBG) Log.d(TAG, "Sending ndef via SNEP"); - int snepResult = doSnepProtocol(mHandoverManager, m, uris); + int snepResult = doSnepProtocol(mHandoverManager, m, uris, + mDefaultMiu, mDefaultRwSize); switch (snepResult) { case SNEP_HANDOVER_UNSUPPORTED: @@ -461,8 +467,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba } static int doSnepProtocol(HandoverManager handoverManager, - NdefMessage msg, Uri[] uris) throws IOException { - SnepClient snepClient = new SnepClient(); + NdefMessage msg, Uri[] uris, int miu, int rwSize) throws IOException { + SnepClient snepClient = new SnepClient(miu, rwSize); try { snepClient.connect(); } catch (IOException e) { diff --git a/src/com/android/nfc/snep/SnepClient.java b/src/com/android/nfc/snep/SnepClient.java index 8dca6ae..fae8143 100644 --- a/src/com/android/nfc/snep/SnepClient.java +++ b/src/com/android/nfc/snep/SnepClient.java @@ -29,7 +29,8 @@ public final class SnepClient { private static final String TAG = "SnepClient"; private static final boolean DBG = false; private static final int DEFAULT_ACCEPTABLE_LENGTH = 100*1024; - private static final int MIU = 128; + private static final int DEFAULT_MIU = 128; + private static final int DEFAULT_RWSIZE = 1; SnepMessenger mMessenger = null; private final Object mTransmissionLock = new Object(); @@ -38,6 +39,8 @@ public final class SnepClient { private int mState = DISCONNECTED; private final int mAcceptableLength; private final int mFragmentLength; + private final int mMiu; + private final int mRwSize; private static final int DISCONNECTED = 0; private static final int CONNECTING = 1; @@ -48,6 +51,8 @@ public final class SnepClient { mPort = SnepServer.DEFAULT_PORT; mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; mFragmentLength = -1; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RWSIZE; } public SnepClient(String serviceName) { @@ -55,6 +60,17 @@ public final class SnepClient { mPort = -1; mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; mFragmentLength = -1; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RWSIZE; + } + + public SnepClient(int miu, int rwSize) { + mServiceName = SnepServer.DEFAULT_SERVICE_NAME; + mPort = SnepServer.DEFAULT_PORT; + mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; + mFragmentLength = -1; + mMiu = miu; + mRwSize = rwSize; } SnepClient(String serviceName, int fragmentLength) { @@ -62,6 +78,8 @@ public final class SnepClient { mPort = -1; mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; mFragmentLength = fragmentLength; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RWSIZE; } SnepClient(String serviceName, int acceptableLength, int fragmentLength) { @@ -69,6 +87,8 @@ public final class SnepClient { mPort = -1; mAcceptableLength = acceptableLength; mFragmentLength = fragmentLength; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RWSIZE; } public void put(NdefMessage msg) throws IOException { @@ -122,7 +142,7 @@ public final class SnepClient { try { if (DBG) Log.d(TAG, "about to create socket"); // Connect to the snep server on the remote side - socket = NfcService.getInstance().createLlcpSocket(0, MIU, 1, 1024); + socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024); if (socket == null) { throw new IOException("Could not connect to socket."); } diff --git a/src/com/android/nfc/snep/SnepServer.java b/src/com/android/nfc/snep/SnepServer.java index 84bb673..aa7da48 100644 --- a/src/com/android/nfc/snep/SnepServer.java +++ b/src/com/android/nfc/snep/SnepServer.java @@ -34,9 +34,10 @@ import java.io.IOException; public final class SnepServer { private static final String TAG = "SnepServer"; private static final boolean DBG = false; + private static final int DEFAULT_MIU = 248; + private static final int DEFAULT_RW_SIZE = 1; public static final int DEFAULT_PORT = 4; - private static final int MIU = 248; public static final String DEFAULT_SERVICE_NAME = "urn:nfc:sn:snep"; @@ -44,6 +45,8 @@ public final class SnepServer { final String mServiceName; final int mServiceSap; final int mFragmentLength; + final int mMiu; + final int mRwSize; /** Protected by 'this', null when stopped, non-null when running */ ServerThread mServerThread = null; @@ -59,6 +62,8 @@ public final class SnepServer { mServiceName = DEFAULT_SERVICE_NAME; mServiceSap = DEFAULT_PORT; mFragmentLength = -1; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RW_SIZE; } public SnepServer(String serviceName, int serviceSap, Callback callback) { @@ -66,6 +71,17 @@ public final class SnepServer { mServiceName = serviceName; mServiceSap = serviceSap; mFragmentLength = -1; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RW_SIZE; + } + + public SnepServer(Callback callback, int miu, int rwSize) { + mCallback = callback; + mServiceName = DEFAULT_SERVICE_NAME; + mServiceSap = DEFAULT_PORT; + mFragmentLength = -1; + mMiu = miu; + mRwSize = rwSize; } SnepServer(String serviceName, int serviceSap, int fragmentLength, Callback callback) { @@ -73,6 +89,8 @@ public final class SnepServer { mServiceName = serviceName; mServiceSap = serviceSap; mFragmentLength = fragmentLength; + mMiu = DEFAULT_MIU; + mRwSize = DEFAULT_RW_SIZE; } /** Connection class, used to handle incoming connections */ @@ -168,7 +186,7 @@ public final class SnepServer { try { synchronized (SnepServer.this) { mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap, - mServiceName, MIU, 1, 1024); + mServiceName, mMiu, mRwSize, 1024); } if (mServerSocket == null) { if (DBG) Log.d(TAG, "failed to create LLCP service socket"); -- cgit v1.1 From 3c47e69e330d6d2890afae3b0b447954fbb97911 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 7 Aug 2012 18:13:08 -0700 Subject: Fix one last user of astl to use stlport instead... This wasn't directly referencing libastl, so I didn't find it first time round. A top level rebuild without external/astl caught it. I've since grepped and there are no other projects that pull in the include files without the shared library. Change-Id: I2dd06727098744076a7e115d05a8139029ff977a --- nci/jni/Android.mk | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk index a1fb83e..cdcd34e 100644 --- a/nci/jni/Android.mk +++ b/nci/jni/Android.mk @@ -20,7 +20,9 @@ endef LOCAL_SRC_FILES:= $(call all-cpp-files-under, .) LOCAL_C_INCLUDES += \ - external/astl/include \ + bionic \ + bionic/libstdc++ \ + external/stlport/stlport \ external/libxml2/include \ external/icu4c/common \ $(NFA)/include \ @@ -37,7 +39,8 @@ LOCAL_SHARED_LIBRARIES := \ libnativehelper \ libcutils \ libutils \ - libnfc-nci + libnfc-nci \ + libstlport LOCAL_STATIC_LIBRARIES := libxml2 -- cgit v1.1 From 341fbf46e459073c929cb20fcb231ad981b0c67d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 8 Aug 2012 17:19:06 -0700 Subject: Support for setting p2p target/initiator modes in NCI. Allows selectively enabling / disabling p2p modes in the NCI stack. TODO: - Support selecting individual Nfc-F speeds (212/424). - Support disabling initiator Nfc-A / Nfc-F just for NFC-DEP. Change-Id: I55a08bd83640b45e2d8346587031f49213a0860b --- nci/jni/NativeNfcManager.cpp | 19 +++++++++++++++++++ nci/jni/PeerToPeer.cpp | 13 +++++++++++++ nci/jni/PeerToPeer.h | 12 ++++++++++++ 3 files changed, 44 insertions(+) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index eeb74ce..5baa842 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -1431,6 +1431,17 @@ static jstring nfcManager_doDump(JNIEnv *e, jobject o) static void nfcManager_doSetP2pInitiatorModes (JNIEnv *e, jobject o, jint modes) { ALOGD ("%s: modes=0x%X", __FUNCTION__, modes); + struct nfc_jni_native_data *nat = getNative(e, o); + + tNFA_TECHNOLOGY_MASK mask = 0; + if (modes & 0x01) mask |= NFA_TECHNOLOGY_MASK_A; + if (modes & 0x02) mask |= NFA_TECHNOLOGY_MASK_F; + if (modes & 0x04) mask |= NFA_TECHNOLOGY_MASK_F; + if (modes & 0x08) mask |= NFA_TECHNOLOGY_MASK_A_ACTIVE; + if (modes & 0x10) mask |= NFA_TECHNOLOGY_MASK_F_ACTIVE; + if (modes & 0x20) mask |= NFA_TECHNOLOGY_MASK_F_ACTIVE; + nat->tech_mask = mask; + //this function is not called by the NFC service nor exposed by public API. } @@ -1450,6 +1461,14 @@ static void nfcManager_doSetP2pInitiatorModes (JNIEnv *e, jobject o, jint modes) static void nfcManager_doSetP2pTargetModes (JNIEnv *e, jobject o, jint modes) { ALOGD ("%s: modes=0x%X", __FUNCTION__, modes); + // Map in the right modes + tNFA_TECHNOLOGY_MASK mask = 0; + if (modes & 0x01) mask |= NFA_TECHNOLOGY_MASK_A; + if (modes & 0x02) mask |= NFA_TECHNOLOGY_MASK_F; + if (modes & 0x04) mask |= NFA_TECHNOLOGY_MASK_F; + if (modes & 0x08) mask |= NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE; + + PeerToPeer::getInstance().setP2pListenMask(mask); //this function is not called by the NFC service nor exposed by public API. } diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index d98aba5..da3dbad 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -1342,6 +1342,19 @@ UINT8 PeerToPeer::getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle) return pConn->mRemoteRecvWindow; } +/******************************************************************************* +** +** Function: setP2pListenMask +** +** Description: Sets the p2p listen technology mask. +** p2pListenMask: the p2p listen mask to be set? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask) { + mP2pListenTechMask = p2pListenMask; +} /******************************************************************************* ** diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index 166a6ac..e7fcbf8 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -285,6 +285,18 @@ public: /******************************************************************************* ** + ** Function: setP2pListenMask + ** + ** Description: Sets the p2p listen technology mask. + ** p2pListenMask: the p2p listen mask to be set? + ** + ** Returns: None + ** + *******************************************************************************/ + void setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask); + + /******************************************************************************* + ** ** Function: enableP2pListening ** ** Description: Start/stop polling/listening to peer that supports P2P. -- cgit v1.1 From c6cdbf21958178025010c6bed797ff193c89884f Mon Sep 17 00:00:00 2001 From: mike wakerly Date: Thu, 2 Aug 2012 15:45:47 -0700 Subject: NfcService: hold a wake lock around transceive(). Bug: 6629750 Change-Id: Idee36983952b4ba593464f72188c6fb702c59f7f --- src/com/android/nfc/NfcService.java | 94 ++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 13f224b..5f9fc21 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -186,7 +186,10 @@ public class NfcService extends Application implements DeviceHostListener { private DeviceHost mDeviceHost; private SharedPreferences mPrefs; private SharedPreferences.Editor mPrefsEditor; - private PowerManager.WakeLock mWakeLock; + private PowerManager.WakeLock mRoutingWakeLock; + private PowerManager.WakeLock mOpenWakeLock; + private PowerManager.WakeLock mDisconnectWakeLock; + private PowerManager.WakeLock mTransceiveWakeLock; int mStartSound; int mEndSound; int mErrorSound; @@ -320,7 +323,17 @@ public class NfcService extends Application implements DeviceHostListener { mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); - mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService"); + // TODO(mikey|maco): consolidate as a single wakelock when individual + // stats are no longer useful. + mRoutingWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock"); + mOpenWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mOpenWakeLock"); + mDisconnectWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mDisconnectWakeLock"); + mTransceiveWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mTransceiveWakeLock"); + mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); mScreenState = checkScreenState(); @@ -403,6 +416,37 @@ public class NfcService extends Application implements DeviceHostListener { } } + int doOpenSecureElementConnection() { + mOpenWakeLock.acquire(); + try { + return mSecureElement.doOpenSecureElementConnection(); + } finally { + mOpenWakeLock.release(); + } + } + + byte[] doTransceive(int handle, byte[] cmd) { + mTransceiveWakeLock.acquire(); + try { + return doTransceiveNoLock(handle, cmd); + } finally { + mTransceiveWakeLock.release(); + } + } + + byte[] doTransceiveNoLock(int handle, byte[] cmd) { + return mSecureElement.doTransceive(handle, cmd); + } + + void doDisconnect(int handle) { + mDisconnectWakeLock.acquire(); + try { + mSecureElement.doDisconnect(handle); + } finally { + mDisconnectWakeLock.release(); + } + } + /** * Manages tasks that involve turning on/off the NFC controller. * @@ -587,7 +631,7 @@ public class NfcService extends Application implements DeviceHostListener { } } Log.i(TAG, "Executing SE wipe"); - int handle = mSecureElement.doOpenSecureElementConnection(); + int handle = doOpenSecureElementConnection(); if (handle == 0) { Log.w(TAG, "Could not open the secure element"); if (tempEnable) { @@ -596,19 +640,27 @@ public class NfcService extends Application implements DeviceHostListener { return; } - mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000); + try { + mTransceiveWakeLock.acquire(); + try { + mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000); - for (byte[] cmd : apdus) { - byte[] resp = mSecureElement.doTransceive(handle, cmd); - if (resp == null) { - Log.w(TAG, "Transceive failed, could not wipe NFC-EE"); - break; + for (byte[] cmd : apdus) { + byte[] resp = doTransceiveNoLock(handle, cmd); + if (resp == null) { + Log.w(TAG, "Transceive failed, could not wipe NFC-EE"); + break; + } + } + + mDeviceHost.resetTimeouts(); + } finally { + mTransceiveWakeLock.release(); } + } finally { + doDisconnect(handle); } - mDeviceHost.resetTimeouts(); - mSecureElement.doDisconnect(handle); - if (tempEnable) { disableInternal(); } @@ -1189,7 +1241,7 @@ public class NfcService extends Application implements DeviceHostListener { binder.unlinkToDeath(mOpenEe, 0); mDeviceHost.resetTimeouts(); - mSecureElement.doDisconnect(mOpenEe.handle); + doDisconnect(mOpenEe.handle); mOpenEe = null; applyRouting(true); @@ -1232,7 +1284,7 @@ public class NfcService extends Application implements DeviceHostListener { throw new IOException("NFC EE already open"); } - int handle = mSecureElement.doOpenSecureElementConnection(); + int handle = doOpenSecureElementConnection(); if (handle == 0) { throw new IOException("NFC EE failed to open"); } @@ -1296,7 +1348,7 @@ public class NfcService extends Application implements DeviceHostListener { } } - return mSecureElement.doTransceive(mOpenEe.handle, data); + return doTransceive(mOpenEe.handle, data); } @Override @@ -1796,13 +1848,11 @@ public class NfcService extends Application implements DeviceHostListener { } mScreenState = params[0].intValue(); - boolean needWakelock = mScreenState == SCREEN_STATE_OFF; - if (needWakelock) { - mWakeLock.acquire(); - } - applyRouting(false); - if (needWakelock) { - mWakeLock.release(); + mRoutingWakeLock.acquire(); + try { + applyRouting(false); + } finally { + mRoutingWakeLock.release(); } return null; } -- cgit v1.1 From 5c7b8d9beeb46cba30bffaf94945ef6fc55e8a76 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Fri, 10 Aug 2012 17:42:09 -0400 Subject: Remove whitespace from NFC NCI JNI. - Logging changes - Upgrade to stack NFA_MI_1.03.33 Change-Id: Iba2af1af49a261de50f79572b478838e2bdc890f --- nci/jni/Android.mk | 3 +- nci/jni/CondVar.cpp | 14 +-- nci/jni/CondVar.h | 12 +- nci/jni/DataQueue.cpp | 32 ++--- nci/jni/DataQueue.h | 28 ++--- nci/jni/HostAidRouter.cpp | 1 + nci/jni/IntervalTimer.cpp | 6 +- nci/jni/IntervalTimer.h | 2 +- nci/jni/Mutex.cpp | 22 ++-- nci/jni/Mutex.h | 42 +++---- nci/jni/NativeLlcpConnectionlessSocket.cpp | 21 ++-- nci/jni/NativeLlcpServiceSocket.cpp | 9 +- nci/jni/NativeLlcpSocket.cpp | 28 ++--- nci/jni/NativeNfcManager.cpp | 148 ++++++++++++----------- nci/jni/NativeNfcTag.cpp | 117 +++++++++--------- nci/jni/NativeP2pDevice.cpp | 5 +- nci/jni/NativeSecureElement.cpp | 20 +-- nci/jni/NfcJniUtil.cpp | 18 +-- nci/jni/NfcJniUtil.h | 14 +-- nci/jni/NfcTag.cpp | 50 ++++---- nci/jni/NfcTag.h | 36 +++--- nci/jni/PeerToPeer.cpp | 187 +++++++++++++---------------- nci/jni/PeerToPeer.h | 177 +++++++++++++-------------- nci/jni/PowerSwitch.cpp | 53 ++++---- nci/jni/PowerSwitch.h | 64 +++++----- nci/jni/RouteDataSet.cpp | 30 ++--- nci/jni/RouteDataSet.h | 36 +++--- nci/jni/SecureElement.cpp | 175 +++++++++++++-------------- nci/jni/SecureElement.h | 102 ++++++++-------- nci/jni/SyncEvent.h | 66 +++++----- 30 files changed, 746 insertions(+), 772 deletions(-) diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk index cdcd34e..335e5f1 100644 --- a/nci/jni/Android.mk +++ b/nci/jni/Android.mk @@ -41,10 +41,11 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libnfc-nci \ libstlport - + LOCAL_STATIC_LIBRARIES := libxml2 LOCAL_MODULE := libnfc_nci_jni LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) + diff --git a/nci/jni/CondVar.cpp b/nci/jni/CondVar.cpp index cb67825..1156344 100644 --- a/nci/jni/CondVar.cpp +++ b/nci/jni/CondVar.cpp @@ -19,7 +19,7 @@ ** Function: CondVar ** ** Description: Initialize member variables. -** +** ** Returns: None. ** *******************************************************************************/ @@ -39,7 +39,7 @@ CondVar::CondVar () ** Function: ~CondVar ** ** Description: Cleanup all resources. -** +** ** Returns: None. ** *******************************************************************************/ @@ -58,13 +58,13 @@ CondVar::~CondVar () ** Function: wait ** ** Description: Block the caller and wait for a condition. -** +** ** Returns: None. ** *******************************************************************************/ void CondVar::wait (Mutex& mutex) { - int const res = pthread_cond_wait (&mCondition, mutex.nativeHandle()); + int const res = pthread_cond_wait (&mCondition, mutex.nativeHandle()); if (res) { ALOGE ("CondVar::wait: fail wait; error=0x%X", res); @@ -78,7 +78,7 @@ void CondVar::wait (Mutex& mutex) ** ** Description: Block the caller and wait for a condition. ** millisec: Timeout in milliseconds. -** +** ** Returns: True if wait is successful; false if timeout occurs. ** *******************************************************************************/ @@ -103,7 +103,7 @@ bool CondVar::wait (Mutex& mutex, long millisec) else absoluteTime.tv_nsec = ns; } - + //pthread_cond_timedwait_monotonic_np() is an Android-specific function //declared in /development/ndk/platforms/android-9/include/pthread.h; //it uses monotonic clock. @@ -121,7 +121,7 @@ bool CondVar::wait (Mutex& mutex, long millisec) ** Function: notifyOne ** ** Description: Unblock the waiting thread. -** +** ** Returns: None. ** *******************************************************************************/ diff --git a/nci/jni/CondVar.h b/nci/jni/CondVar.h index bfe4dfb..eca17aa 100644 --- a/nci/jni/CondVar.h +++ b/nci/jni/CondVar.h @@ -22,7 +22,7 @@ public: ** Function: CondVar ** ** Description: Initialize member variables. - ** + ** ** Returns: None. ** *******************************************************************************/ @@ -34,7 +34,7 @@ public: ** Function: ~CondVar ** ** Description: Cleanup all resources. - ** + ** ** Returns: None. ** *******************************************************************************/ @@ -46,7 +46,7 @@ public: ** Function: wait ** ** Description: Block the caller and wait for a condition. - ** + ** ** Returns: None. ** *******************************************************************************/ @@ -59,7 +59,7 @@ public: ** ** Description: Block the caller and wait for a condition. ** millisec: Timeout in milliseconds. - ** + ** ** Returns: True if wait is successful; false if timeout occurs. ** *******************************************************************************/ @@ -71,12 +71,12 @@ public: ** Function: notifyOne ** ** Description: Unblock the waiting thread. - ** + ** ** Returns: None. ** *******************************************************************************/ void notifyOne (); - + private: pthread_cond_t mCondition; }; \ No newline at end of file diff --git a/nci/jni/DataQueue.cpp b/nci/jni/DataQueue.cpp index 2b07c7e..ab94734 100644 --- a/nci/jni/DataQueue.cpp +++ b/nci/jni/DataQueue.cpp @@ -14,10 +14,10 @@ /******************************************************************************* ** -** Function: DataQueue +** Function: DataQueue +** +** Description: Initialize member variables. ** -** Description: Initialize member variables. -** ** Returns: None. ** *******************************************************************************/ @@ -28,10 +28,10 @@ DataQueue::DataQueue () /******************************************************************************* ** -** Function: ~DataQueue +** Function: ~DataQueue +** +** Description: Release all resources. ** -** Description: Release all resources. -** ** Returns: None. ** *******************************************************************************/ @@ -48,8 +48,8 @@ DataQueue::~DataQueue () } -bool DataQueue::isEmpty() -{ +bool DataQueue::isEmpty() +{ mMutex.lock (); bool retval = mQueue.empty(); mMutex.unlock (); @@ -59,12 +59,12 @@ bool DataQueue::isEmpty() /******************************************************************************* ** -** Function: enqueue +** Function: enqueue ** ** Description: Append data to the queue. ** data: array of bytes ** dataLen: length of the data. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -72,18 +72,18 @@ bool DataQueue::enqueue (UINT8* data, UINT16 dataLen) { if ((data == NULL) || (dataLen==0)) return false; - + mMutex.lock (); - + bool retval = false; tHeader* header = (tHeader*) malloc (sizeof(tHeader) + dataLen); - + if (header) { memset (header, 0, sizeof(tHeader)); header->mDataLen = dataLen; memcpy (header+1, data, dataLen); - + mQueue.push_back (header); retval = true; @@ -99,13 +99,13 @@ bool DataQueue::enqueue (UINT8* data, UINT16 dataLen) /******************************************************************************* ** -** Function: dequeue +** Function: dequeue ** ** Description: Retrieve and remove data from the front of the queue. ** buffer: array to store the data. ** bufferMaxLen: maximum size of the buffer. ** actualLen: actual length of the data. -** +** ** Returns: True if ok. ** *******************************************************************************/ diff --git a/nci/jni/DataQueue.h b/nci/jni/DataQueue.h index 4c0c454..4bb6bda 100644 --- a/nci/jni/DataQueue.h +++ b/nci/jni/DataQueue.h @@ -8,7 +8,7 @@ ** Proprietary and confidential. ** *****************************************************************************/ - + #pragma once #include "NfcJniUtil.h" #include "gki.h" @@ -21,10 +21,10 @@ class DataQueue public: /******************************************************************************* ** - ** Function: DataQueue + ** Function: DataQueue + ** + ** Description: Initialize member variables. ** - ** Description: Initialize member variables. - ** ** Returns: None. ** *******************************************************************************/ @@ -33,10 +33,10 @@ public: /******************************************************************************* ** - ** Function: ~DataQueue + ** Function: ~DataQueue + ** + ** Description: Release all resources. ** - ** Description: Release all resources. - ** ** Returns: None. ** *******************************************************************************/ @@ -45,12 +45,12 @@ public: /******************************************************************************* ** - ** Function: enqueue + ** Function: enqueue ** ** Description: Append data to the queue. ** data: array of bytes ** dataLen: length of the data. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -59,13 +59,13 @@ public: /******************************************************************************* ** - ** Function: dequeue + ** Function: dequeue ** ** Description: Retrieve and remove data from the front of the queue. ** buffer: array to store the data. ** bufferMaxLen: maximum size of the buffer. ** actualLen: actual length of the data. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -74,15 +74,15 @@ public: /******************************************************************************* ** - ** Function: isEmpty + ** Function: isEmpty ** ** Description: Whether the queue is empty. - ** + ** ** Returns: True if empty. ** *******************************************************************************/ bool isEmpty(); - + private: struct tHeader { diff --git a/nci/jni/HostAidRouter.cpp b/nci/jni/HostAidRouter.cpp index dd54d19..5b32608 100644 --- a/nci/jni/HostAidRouter.cpp +++ b/nci/jni/HostAidRouter.cpp @@ -8,6 +8,7 @@ ** Proprietary and confidential. ** *****************************************************************************/ +#include "OverrideLog.h" #include "HostAidRouter.h" #include "config.h" #include "SecureElement.h" diff --git a/nci/jni/IntervalTimer.cpp b/nci/jni/IntervalTimer.cpp index 4cca01a..304fa7e 100644 --- a/nci/jni/IntervalTimer.cpp +++ b/nci/jni/IntervalTimer.cpp @@ -10,9 +10,9 @@ *****************************************************************************/ #include "IntervalTimer.h" -#include +#include "OverrideLog.h" + - IntervalTimer::IntervalTimer() { mTimerId = NULL; @@ -73,7 +73,7 @@ bool IntervalTimer::create(TIMER_FUNC cb) { struct sigevent se; int stat = 0; - + /* * Set the sigevent structure to cause the signal to be * delivered by creating a new thread. diff --git a/nci/jni/IntervalTimer.h b/nci/jni/IntervalTimer.h index 0f1095f..e3ec1c6 100644 --- a/nci/jni/IntervalTimer.h +++ b/nci/jni/IntervalTimer.h @@ -22,7 +22,7 @@ public: bool set(int ms, TIMER_FUNC cb); void kill(); bool create(TIMER_FUNC ); - + private: timer_t mTimerId; TIMER_FUNC mCb; diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp index 4034a03..a6b1397 100644 --- a/nci/jni/Mutex.cpp +++ b/nci/jni/Mutex.cpp @@ -15,10 +15,10 @@ /******************************************************************************* ** -** Function: Mutex +** Function: Mutex ** ** Description: Initialize member variables. -** +** ** Returns: None. ** *******************************************************************************/ @@ -35,10 +35,10 @@ Mutex::Mutex () /******************************************************************************* ** -** Function: ~Mutex +** Function: ~Mutex ** ** Description: Cleanup all resources. -** +** ** Returns: None. ** *******************************************************************************/ @@ -54,10 +54,10 @@ Mutex::~Mutex () /******************************************************************************* ** -** Function: lock +** Function: lock ** ** Description: Block the thread and try lock the mutex. -** +** ** Returns: None. ** *******************************************************************************/ @@ -73,10 +73,10 @@ void Mutex::lock () /******************************************************************************* ** -** Function: unlock +** Function: unlock ** ** Description: Unlock a mutex to unblock a thread. -** +** ** Returns: None. ** *******************************************************************************/ @@ -92,10 +92,10 @@ void Mutex::unlock () /******************************************************************************* ** -** Function: tryLock +** Function: tryLock ** ** Description: Try to lock the mutex. -** +** ** Returns: True if the mutex is locked. ** *******************************************************************************/ @@ -115,7 +115,7 @@ bool Mutex::tryLock () ** Function: nativeHandle ** ** Description: Get the handle of the mutex. -** +** ** Returns: Handle of the mutex. ** *******************************************************************************/ diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h index c858e8e..bd762c2 100644 --- a/nci/jni/Mutex.h +++ b/nci/jni/Mutex.h @@ -18,75 +18,75 @@ class Mutex public: /******************************************************************************* ** - ** Function: Mutex + ** Function: Mutex ** ** Description: Initialize member variables. - ** + ** ** Returns: None. ** *******************************************************************************/ Mutex (); - - + + /******************************************************************************* ** - ** Function: ~Mutex + ** Function: ~Mutex ** ** Description: Cleanup all resources. - ** + ** ** Returns: None. ** *******************************************************************************/ ~Mutex (); - - + + /******************************************************************************* ** - ** Function: lock + ** Function: lock ** ** Description: Block the thread and try lock the mutex. - ** + ** ** Returns: None. ** *******************************************************************************/ void lock (); - - + + /******************************************************************************* ** - ** Function: unlock + ** Function: unlock ** ** Description: Unlock a mutex to unblock a thread. - ** + ** ** Returns: None. ** *******************************************************************************/ void unlock (); - - + + /******************************************************************************* ** - ** Function: tryLock + ** Function: tryLock ** ** Description: Try to lock the mutex. - ** + ** ** Returns: True if the mutex is locked. ** *******************************************************************************/ bool tryLock (); - + /******************************************************************************* ** ** Function: nativeHandle ** ** Description: Get the handle of the mutex. - ** + ** ** Returns: Handle of the mutex. ** *******************************************************************************/ pthread_mutex_t* nativeHandle (); - + private: pthread_mutex_t mMutex; }; diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp index 88361a6..2c4618f 100644 --- a/nci/jni/NativeLlcpConnectionlessSocket.cpp +++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp @@ -17,6 +17,7 @@ #include #include +#include "OverrideLog.h" #include "NfcJniUtil.h" extern "C" { @@ -25,7 +26,7 @@ extern "C" } -namespace android +namespace android { @@ -43,7 +44,7 @@ static uint8_t* sConnlessRecvBuf = NULL; static uint32_t sConnlessRecvLen = 0; static uint32_t sConnlessRecvRemoteSap = 0; - + /******************************************************************************* ** ** Function: nativeLlcpConnectionlessSocket_doSendTo @@ -53,7 +54,7 @@ static uint32_t sConnlessRecvRemoteSap = 0; ** o: Java object. ** nsap: service access point. ** data: buffer for data. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -96,7 +97,7 @@ static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, j ** data: buffer contains data. ** len: length of data. ** remoteSap: remote service access point. -** +** ** Returns: None ** *******************************************************************************/ @@ -127,7 +128,7 @@ void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, ui ** Function: connectionlessCleanup ** ** Description: Free resources. -** +** ** Returns: None ** *******************************************************************************/ @@ -149,7 +150,7 @@ static jobject connectionlessCleanup () ** Function: nativeLlcpConnectionlessSocket_abortWait ** ** Description: Abort current operation and unblock threads. -** +** ** Returns: None ** *******************************************************************************/ @@ -167,7 +168,7 @@ void nativeLlcpConnectionlessSocket_abortWait () ** e: JVM environment. ** o: Java object. ** linkMiu: max info unit -** +** ** Returns: LlcpPacket Java object. ** *******************************************************************************/ @@ -237,7 +238,7 @@ static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv *e, jobject e->SetByteArrayRegion (receivedData, 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf); e->SetObjectField (llcpPacket, f, receivedData); -TheEnd: +TheEnd: connectionlessCleanup (); if (sem_destroy (&sConnlessRecvSem)) { @@ -254,7 +255,7 @@ TheEnd: ** Description: Close socket. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -300,7 +301,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp index 8b05b8e..ca57410 100644 --- a/nci/jni/NativeLlcpServiceSocket.cpp +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include "OverrideLog.h" #include "NfcJniUtil.h" #include "NfcAdaptation.h" #include "PeerToPeer.h" @@ -29,7 +30,7 @@ extern tBRCM_JNI_HANDLE gNextJniHandle; namespace android { - + extern char* gNativeLlcpServiceSocketClassName; extern char* gNativeLlcpSocketClassName; @@ -44,7 +45,7 @@ extern char* gNativeLlcpSocketClassName; ** miu: Maximum information unit. ** rw: Receive window. ** linearBufferLength: Not used. -** +** ** Returns: LlcpSocket Java object. ** *******************************************************************************/ @@ -110,7 +111,7 @@ TheEnd: ** Description: Close a server socket. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -147,7 +148,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp index cad6268..f0f0d3d 100644 --- a/nci/jni/NativeLlcpSocket.cpp +++ b/nci/jni/NativeLlcpSocket.cpp @@ -14,14 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "NfcJniUtil.h" +#include "OverrideLog.h" #include "PeerToPeer.h" namespace android { - + extern char* gNativeLlcpSocketClassName; @@ -33,7 +33,7 @@ extern char* gNativeLlcpSocketClassName; ** e: JVM environment. ** o: Java object. ** nSap: Service access point. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -64,7 +64,7 @@ static jboolean nativeLlcpSocket_doConnect (JNIEnv* e, jobject o, jint nSap) ** e: JVM environment. ** o: Java object. ** sn: Service name. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -97,7 +97,7 @@ static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn) ** Description: Close socket. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -125,13 +125,13 @@ static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o) ** e: JVM environment. ** o: Java object. ** data: Buffer of data. -** +** ** Returns: True if sent ok. ** *******************************************************************************/ static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data) { - ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (data, NULL); uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (data); bool stat = false; @@ -142,7 +142,7 @@ static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data) e->ReleaseByteArrayElements (data, (jbyte*) dataBuffer, JNI_ABORT); - ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__); return stat ? JNI_TRUE : JNI_FALSE; } @@ -155,13 +155,13 @@ static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data) ** e: JVM environment. ** o: Java object. ** origBuffer: Buffer to put received data. -** +** ** Returns: Number of bytes received. ** *******************************************************************************/ static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuffer) { - ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__); uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (origBuffer, NULL); uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (origBuffer); uint16_t actualLen = 0; @@ -180,7 +180,7 @@ static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuff retval = -1; e->ReleaseByteArrayElements (origBuffer, (jbyte*) dataBuffer, 0); - ALOGD_IF ((PeerToPeer::getInstance ().getLogLevel ()>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval); return retval; } @@ -192,7 +192,7 @@ static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuff ** Description: Get peer's maximum information unit. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Peer's maximum information unit. ** *******************************************************************************/ @@ -218,7 +218,7 @@ static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o) ** Description: Get peer's receive window size. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Peer's receive window size. ** *******************************************************************************/ @@ -260,7 +260,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 5baa842..0850f8a 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -17,6 +17,7 @@ #include #include +#include "OverrideLog.h" #include "NfcJniUtil.h" #include "NfcAdaptation.h" #include "SyncEvent.h" @@ -116,7 +117,6 @@ static int sConnlessLinkMiu = 0; static bool sAbortConnlessWait = false; static bool sIsSecElemSelected = false; //has NFC service selected a sec elem static UINT8 * sOriginalLptdCfg = NULL; -#define LPTD_PARAM_LEN (30) static UINT8 sNewLptdCfg[LPTD_PARAM_LEN]; static UINT32 sConfigUpdated = 0; #define CONFIG_UPDATE_LPTD (1 << 0) @@ -145,7 +145,7 @@ static void nfaBrcmInitCallback (UINT32 brcm_hw_id); ** Function: getNative ** ** Description: Get native data -** +** ** Returns: Native data structure. ** *******************************************************************************/ @@ -166,7 +166,7 @@ nfc_jni_native_data *getNative (JNIEnv* e, jobject o) ** ** Description: Handle RF-discovery events from the stack. ** discoveredDevice: Discovered device. -** +** ** Returns: None ** *******************************************************************************/ @@ -199,7 +199,7 @@ static void handleRfDiscoveryEvent (tNFC_RESULT_DEVT* discoveredDevice) ** Description: Receive connection-related events from stack. ** connEvent: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -235,7 +235,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat sNfaEnableDisablePollingEvent.notifyOne (); } break; - + case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started { ALOGD("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __FUNCTION__, eventData->status); @@ -244,7 +244,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat sNfaEnableDisablePollingEvent.notifyOne (); } break; - + case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event { ALOGD("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __FUNCTION__, eventData->status); @@ -253,7 +253,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat sNfaEnableDisablePollingEvent.notifyOne (); } break; - + case NFA_DISC_RESULT_EVT: // NFC link/protocol discovery notificaiton status = eventData->disc_result.status; ALOGD("%s: NFA_DISC_RESULT_EVT: status = %d", __FUNCTION__, status); @@ -419,12 +419,12 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat ALOGD("%s: NFA_CE_UICC_LISTEN_CONFIGURED_EVT : status=0x%X", __FUNCTION__, eventData->status); SecureElement::getInstance().connectionEventHandler (connEvent, eventData); break; - + case NFA_SET_P2P_LISTEN_TECH_EVT: ALOGD("%s: NFA_SET_P2P_LISTEN_TECH_EVT", __FUNCTION__); PeerToPeer::getInstance().connectionEventHandler (connEvent, eventData); break; - + default: ALOGE("%s: unknown event ????", __FUNCTION__); break; @@ -439,7 +439,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat ** Description: Initialize variables. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -515,7 +515,7 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) } PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); - + ALOGD ("%s: exit", __FUNCTION__); return JNI_TRUE; } @@ -528,7 +528,7 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) ** Description: Receive device management events from stack. ** dmEvent: Device-management event ID. ** eventData: Data associated with event ID. -** +** ** Returns: None ** *******************************************************************************/ @@ -627,6 +627,7 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) case NFA_DM_PWR_MODE_CHANGE_EVT: PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData); break; + case NFA_DM_FIRMWARE_BUILD_INFO_EVT: { tNFA_BRCM_FW_BUILD_INFO* bldInfo = @@ -638,6 +639,7 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) sNfaBuildInfoEvent.notifyOne(); } break; + default: ALOGD ("%s: unhandled event", __FUNCTION__); break; @@ -652,7 +654,7 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) ** Description: Turn on NFC. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -669,29 +671,29 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) { unsigned long num = 0; + tBRCM_DEV_INIT_CONFIG devInitConfig = {0}; NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Initialize(); //start GKI, NCI task, NFC task SyncEventGuard guard (sNfaEnableEvent); - + NFA_Init(); - NFA_BrcmInit (nfaBrcmInitCallback); + NFA_BrcmInit (&devInitConfig, nfaBrcmInitCallback); + stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); if (stat == NFA_STATUS_OK) { - if (GetNumValue (NAME_APPL_TRACE_LEVEL, &num, sizeof (num))) - { - CE_SetTraceLevel (num); - LLCP_SetTraceLevel (num); - NFC_SetTraceLevel (num); - NCI_SetTraceLevel (num); - RW_SetTraceLevel (num); - NFA_SetTraceLevel (num); - NFA_ChoSetTraceLevel (num); - NFA_P2pSetTraceLevel (num); - NFA_SnepSetTraceLevel (num); - } + num = initializeGlobalAppLogLevel (); + CE_SetTraceLevel (num); + LLCP_SetTraceLevel (num); + NFC_SetTraceLevel (num); + NCI_SetTraceLevel (num); + RW_SetTraceLevel (num); + NFA_SetTraceLevel (num); + NFA_ChoSetTraceLevel (num); + NFA_P2pSetTraceLevel (num); + NFA_SnepSetTraceLevel (num); sNfaEnableEvent.wait(); //wait for NFA command to finish //sIsNfaEnabled indicates whether stack started successfully @@ -725,11 +727,11 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask); } - + // Always restore LPTD Configuration to the stack default. if (sOriginalLptdCfg != NULL) p_nfa_dm_lptd_cfg = sOriginalLptdCfg; - + // if this value is not set or set and non-zero, enable multi-technology responses. if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) @@ -767,7 +769,7 @@ TheEnd: ** e: JVM environment. ** o: Java object. ** mode: Not used. -** +** ** Returns: None ** *******************************************************************************/ @@ -790,9 +792,9 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) tNFA_STATUS stat = NFA_STATUS_OK; ALOGD ("%s: sIsSecElemSelected=%u", __FUNCTION__, sIsSecElemSelected); - + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); - + { SyncEventGuard guard (sNfaEnableDisablePollingEvent); stat = NFA_EnablePolling (tech_mask); @@ -819,7 +821,7 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) if (!sIsSecElemSelected) stat = SecureElement::getInstance().routeToDefault (); } - + // Actually start discovery. startRfDiscovery (true); @@ -834,7 +836,7 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) ** Description: Stop polling and listening for devices. ** e: JVM environment. ** o: Java object. -** +** ** Returns: None ** *******************************************************************************/ @@ -851,7 +853,7 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) // Stop RF Discovery. startRfDiscovery (false); - + if (sDiscoveryEnabled) { SyncEventGuard guard (sNfaEnableDisablePollingEvent); @@ -874,7 +876,7 @@ TheEnd: /******************************************************************************* ** -** Function nfc_jni_cache_object_local +** Function nfc_jni_cache_object_local ** ** Description Allocates a java object and calls it's constructor ** @@ -886,14 +888,14 @@ int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cache jclass cls = NULL; jobject obj = NULL; jmethodID ctor = 0; - + cls = e->FindClass (className); if(cls == NULL) { ALOGE ("%s: find class error", __FUNCTION__); return -1; } - + ctor = e->GetMethodID (cls, "", "()V"); obj = e->NewObject (cls, ctor); if (obj == NULL) @@ -901,7 +903,7 @@ int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cache ALOGE ("%s: create object error", __FUNCTION__); return -1; } - + *cachedObj = e->NewLocalRef (obj); if (*cachedObj == NULL) { @@ -926,7 +928,7 @@ int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cache ** miu: Maximum information unit. ** rw: Receive window size. ** linearBufferLength: Max buffer size. -** +** ** Returns: NativeLlcpServiceSocket Java object. ** *******************************************************************************/ @@ -998,7 +1000,7 @@ static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject o, jint ** Description: Get the last error code. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Last error code. ** *******************************************************************************/ @@ -1016,7 +1018,7 @@ static jint nfcManager_doGetLastError(JNIEnv* e, jobject o) ** Description: Turn off NFC. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1077,7 +1079,7 @@ static jboolean nfcManager_doDeinitialize (JNIEnv* e, jobject o) ** miu: Maximum information unit. ** rw: Receive window size. ** linearBufferLength: Max buffer size. -** +** ** Returns: NativeLlcpSocket Java object. ** *******************************************************************************/ @@ -1139,7 +1141,7 @@ TheEnd: ** o: Java object. ** nSap: Service access point. ** sn: Service name. -** +** ** Returns: NativeLlcpConnectionlessSocket Java object. ** *******************************************************************************/ @@ -1157,7 +1159,7 @@ static jobject nfcManager_doCreateLlcpConnectionlessSocket (JNIEnv *e, jobject o ** Description: Get a list of secure element handles. ** e: JVM environment. ** o: Java object. -** +** ** Returns: List of secure element handles. ** *******************************************************************************/ @@ -1175,7 +1177,7 @@ static jintArray nfcManager_doGetSecureElementList(JNIEnv *e, jobject o) ** Description: NFC controller starts routing data in listen mode. ** e: JVM environment. ** o: Java object. -** +** ** Returns: None ** *******************************************************************************/ @@ -1215,7 +1217,7 @@ TheEnd: ** Description: NFC controller stops routing data in listen mode. ** e: JVM environment. ** o: Java object. -** +** ** Returns: None ** *******************************************************************************/ @@ -1237,10 +1239,10 @@ static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) sIsSecElemSelected = false; goto TheEnd; } - + stat = SecureElement::getInstance().routeToDefault (); sIsSecElemSelected = false; - + //if controller is not routing to sec elems AND there is no pipe connected, //then turn off the sec elems if (SecureElement::getInstance().isBusy() == false) @@ -1261,7 +1263,7 @@ TheEnd: ** ** Description: Whether the activation data indicates the peer supports NFC-DEP. ** activated: Activation data. -** +** ** Returns: True if the peer supports NFC-DEP. ** *******************************************************************************/ @@ -1276,7 +1278,7 @@ static bool isPeerToPeer (tNFA_ACTIVATED& activated) ** Function: nfcManager_doCheckLlcp ** ** Description: Not used. -** +** ** Returns: True ** *******************************************************************************/ @@ -1292,7 +1294,7 @@ static jboolean nfcManager_doCheckLlcp(JNIEnv *e, jobject o) ** Function: nfcManager_doActivateLlcp ** ** Description: Not used. -** +** ** Returns: True ** *******************************************************************************/ @@ -1308,7 +1310,7 @@ static jboolean nfcManager_doActivateLlcp(JNIEnv *e, jobject o) ** Function: nfcManager_doAbort ** ** Description: Not used. -** +** ** Returns: None ** *******************************************************************************/ @@ -1323,7 +1325,7 @@ static void nfcManager_doAbort(JNIEnv *e, jobject o) ** Function: nfcManager_doDownload ** ** Description: Not used. -** +** ** Returns: True ** *******************************************************************************/ @@ -1339,11 +1341,11 @@ static jboolean nfcManager_doDownload(JNIEnv *e, jobject o) ** Function: nfcManager_doResetTimeouts ** ** Description: Not used. -** +** ** Returns: None ** *******************************************************************************/ -static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o) +static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o) { ALOGD ("%s: %d millisec", __FUNCTION__, DEFAULT_GENERAL_TRANS_TIMEOUT); gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT; @@ -1358,13 +1360,13 @@ static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o) ** e: JVM environment. ** o: Java object. ** timeout: Timeout value. -** +** ** Returns: True if ok. ** *******************************************************************************/ -static bool nfcManager_doSetTimeout(JNIEnv *e, jobject o, jint tech, jint timeout) +static bool nfcManager_doSetTimeout(JNIEnv *e, jobject o, jint tech, jint timeout) { - if (timeout <= 0) + if (timeout <= 0) { ALOGE("%s: Timeout must be positive.",__FUNCTION__); return false; @@ -1384,7 +1386,7 @@ static bool nfcManager_doSetTimeout(JNIEnv *e, jobject o, jint tech, jint timeou ** e: JVM environment. ** o: Java object. ** tech: Not used. -** +** ** Returns: Timeout value. ** *******************************************************************************/ @@ -1402,7 +1404,7 @@ static jint nfcManager_doGetTimeout(JNIEnv *e, jobject o, jint tech) ** Description: Not used. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Text dump. ** *******************************************************************************/ @@ -1476,7 +1478,7 @@ static void nfcManager_doSetP2pTargetModes (JNIEnv *e, jobject o, jint modes) ** ** Function nfcManager_doSetScreenState ** -** Description Forward the Screen On/Off state to native code for enhanced +** Description Forward the Screen On/Off state to native code for enhanced ** power saving mode. ** ** Returns true @@ -1573,7 +1575,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ @@ -1593,7 +1595,7 @@ int register_com_android_nfc_NativeNfcManager (JNIEnv *e) ** ** Description: Ask stack to start polling and listening for devices. ** isStart: Whether to start. -** +** ** Returns: None ** *******************************************************************************/ @@ -1601,7 +1603,7 @@ void startRfDiscovery(bool isStart) { SyncEventGuard guard (sNfaEnableDisablePollingEvent); tNFA_STATUS status = NFA_STATUS_FAILED; - + ALOGD ("%s: is start=%d", __FUNCTION__, isStart); status = isStart ? NFA_StartRfDiscovery () : NFA_StopRfDiscovery (); @@ -1621,7 +1623,7 @@ void startRfDiscovery(bool isStart) ** Function: doStartupConfig ** ** Description: Configure the NFC controller. -** +** ** Returns: None ** *******************************************************************************/ @@ -1629,7 +1631,7 @@ void doStartupConfig() { unsigned long num = 0; struct nfc_jni_native_data *nat = getNative(0, 0); - + // Enable the "RC workaround" to allow our stack/firmware to work with a retail // Nexus S that causes IOP issues. Only enable if value exists and set to 1. if (GetNumValue(NAME_USE_NXP_P2P_RC_WORKAROUND, &num, sizeof(num)) && (num == 1)) @@ -1643,7 +1645,7 @@ void doStartupConfig() ALOGD ("%s: Configure RC work-around", __FUNCTION__); NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]); } - + // If polling for Active mode, set the ordering so that we choose Active over Passive mode first. if (nat && (nat->tech_mask & (NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE))) { @@ -1667,14 +1669,14 @@ void doStartupConfig() num *= 1000; UINT8 * p = &swpcfg_param[12]; UINT32_TO_STREAM(p, num) - + NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]); } - + // Set antenna tuning configuration if configured. #define PREINIT_DSP_CFG_SIZE 30 UINT8 preinit_dsp_param[PREINIT_DSP_CFG_SIZE]; - + if (GetStrValue(NAME_PREINIT_DSP_CFG, (char*)&preinit_dsp_param[0], sizeof(preinit_dsp_param))) { NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_param[0]); @@ -1687,7 +1689,7 @@ void doStartupConfig() ** Function: nfcManager_isNfcActive ** ** Description: Used externaly to determine if NFC is active or not. -** +** ** Returns: 'true' if the NFC stack is running, else 'false'. ** *******************************************************************************/ @@ -1710,7 +1712,7 @@ bool nfcManager_isNfcActive() *******************************************************************************/ void nfaBrcmInitCallback (UINT32 brcm_hw_id) { - ALOGD ("%s: enter; brcm_hw_id=0x%X", __FUNCTION__, brcm_hw_id); + ALOGD ("%s: enter; brcm_hw_id=0x%lX", __FUNCTION__, brcm_hw_id); nfa_app_post_nci_reset (brcm_hw_id); } diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index 7a92b44..53c2384 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "OverrideLog.h" #include "NfcJniUtil.h" #include "NfcTag.h" #include "config.h" @@ -59,10 +60,10 @@ namespace android ** private variables and functions ** *****************************************************************************/ -namespace android +namespace android { - + // Pre-defined tag type values. These must match the values in // framework Ndef.java for Google public NFC API. #define NDEF_UNKNOWN_TYPE -1 @@ -78,7 +79,7 @@ static uint32_t sCheckNdefCurrentSize = 0; static tNFA_STATUS sCheckNdefStatus = 0; //whether tag already contains a NDEF message static bool sCheckNdefCapable = false; //whether tag has NDEF capability static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID; -static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP; +static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP; static uint8_t* sTransceiveData = NULL; static uint32_t sTransceiveDataLen = 0; static bool sWaitingForTransceive = false; @@ -118,7 +119,7 @@ static bool switchRfInterface(tNFA_INTF_TYPE rfInterface); ** Function: nativeNfcTag_abortWaits ** ** Description: Unblock all thread synchronization objects. -** +** ** Returns: None ** *******************************************************************************/ @@ -151,7 +152,7 @@ void nativeNfcTag_abortWaits () ** Function: switchBackTimerProc ** ** Description: Callback function for interval timer. -** +** ** Returns: None ** *******************************************************************************/ @@ -169,7 +170,7 @@ static void switchBackTimerProc (union sigval) ** Description: Receive the completion status of read operation. Called by ** NFA_READ_CPLT_EVT. ** status: Status of operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -200,7 +201,7 @@ void nativeNfcTag_doReadCompleted (tNFA_STATUS status) ** Description: Receive NDEF-message related events from stack. ** event: Event code. ** p_data: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -241,7 +242,7 @@ static void ndefHandlerCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *eventD ** Description: Read the NDEF message on the tag. ** e: JVM environment. ** o: Java object. -** +** ** Returns: NDEF message. ** *******************************************************************************/ @@ -302,7 +303,7 @@ static jbyteArray nativeNfcTag_doRead (JNIEnv *e, jobject o) ** Description: Receive the completion status of write operation. Called ** by NFA_WRITE_CPLT_EVT. ** isWriteOk: Status of operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -324,7 +325,7 @@ void nativeNfcTag_doWriteStatus (jboolean isWriteOk) ** Description: Receive the completion status of format operation. Called ** by NFA_FORMAT_CPLT_EVT. ** isOk: Status of operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -343,7 +344,7 @@ void nativeNfcTag_formatStatus (bool isOk) ** e: JVM environment. ** o: Java object. ** buf: Contains a NDEF message. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -436,7 +437,7 @@ TheEnd: ** ** Description: Receive the completion status of connect operation. ** isConnectOk: Status of the operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -457,7 +458,7 @@ void nativeNfcTag_doConnectStatus (jboolean isConnectOk) ** Function: nativeNfcTag_doDeactivateStatus ** ** Description: Receive the completion status of deactivate operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -478,7 +479,7 @@ void nativeNfcTag_doDeactivateStatus (int status) ** e: JVM environment. ** o: Java object. ** targetHandle: Handle of the tag. -** +** ** Returns: Must return NXP status code, which NFC service expects. ** *******************************************************************************/ @@ -521,17 +522,17 @@ static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle) ** ** Function: reSelect ** -** Description: Deactivates the tag and re-selects it with the specified -** rf interface. -** -** Returns: status code, 0 on success, 1 on failure, +** Description: Deactivates the tag and re-selects it with the specified +** rf interface. +** +** Returns: status code, 0 on success, 1 on failure, ** 146 (defined in service) on tag lost ** *******************************************************************************/ static int reSelect (tNFA_INTF_TYPE rfInterface) { ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface); - NfcTag& natTag = NfcTag::getInstance (); + NfcTag& natTag = NfcTag::getInstance (); ALOGD ("%s: NFA_Deactivate()", __FUNCTION__); tNFA_STATUS status; @@ -539,7 +540,7 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) do { - SyncEventGuard g (sReconnectEvent); + SyncEventGuard g (sReconnectEvent); gIsTagDeactivating = true; sGotDeactivate = false; if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) @@ -548,20 +549,20 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) break; } - if (sReconnectEvent.wait (1000) == false) //if timeout occured + if (sReconnectEvent.wait (1000) == false) //if timeout occured { - ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__); + ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__); } if (! NfcTag::getInstance ().isActivated ()) - { + { rVal = STATUS_CODE_TARGET_LOST; break; } gIsTagDeactivating = false; - SyncEventGuard g2 (sReconnectEvent); + SyncEventGuard g2 (sReconnectEvent); sConnectWaitingForComplete = JNI_TRUE; ALOGD ("%s: NFA_Select()", __FUNCTION__); @@ -573,14 +574,14 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) } sConnectOk = false; - if (sReconnectEvent.wait (1000) == false) //if timeout occured + if (sReconnectEvent.wait (1000) == false) //if timeout occured { ALOGE ("%s: wait response timeout", __FUNCTION__); break; } ALOGD("%s: done waiting on NFA_Select() sConnectOk=%d", __FUNCTION__, sConnectOk); if (! NfcTag::getInstance ().isActivated ()) - { + { ALOGD("%s: Tag no longer active", __FUNCTION__); rVal = STATUS_CODE_TARGET_LOST; break; @@ -600,7 +601,7 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) ** ** Description: Switch controller's RF interface to frame, ISO-DEP, or NFC-DEP. ** rfInterface: Type of RF interface. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -639,7 +640,7 @@ static bool switchRfInterface (tNFA_INTF_TYPE rfInterface) ** e: JVM environment. ** o: Java object. ** targetHandle: Handle of the tag. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -657,17 +658,17 @@ static jboolean nativeNfcTag_doConnect_z (JNIEnv *e, jobject o, jint targetHandl ** Description: Re-connect to the tag in RF field. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Status code. ** *******************************************************************************/ static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o) { ALOGD ("%s", __FUNCTION__); - + tNFA_INTF_TYPE intf = NFA_INTERFACE_FRAME; - NfcTag& natTag = NfcTag::getInstance (); - + NfcTag& natTag = NfcTag::getInstance (); + // this is only supported for type 2 or 4 (ISO_DEP) tags if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP) intf = NFA_INTERFACE_ISO_DEP; @@ -688,7 +689,7 @@ static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o) ** Description: Re-connect to the tag in RF field. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -708,7 +709,7 @@ static jboolean nativeNfcTag_doReconnect_z (JNIEnv *e, jobject o) ** e: JVM environment. ** o: Java object. ** targetHandle: Handle of the tag. -** +** ** Returns: Status code. ** *******************************************************************************/ @@ -727,7 +728,7 @@ static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHan ** e: JVM environment. ** o: Java object. ** targetHandle: Handle of the tag. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -745,7 +746,7 @@ static jboolean nativeNfcTag_doHandleReconnect_z (JNIEnv *e, jobject o, jint tar ** Description: Deactivate the RF field. ** e: JVM environment. ** o: Java object. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -780,7 +781,7 @@ TheEnd: ** Description: Receive the completion status of transceive operation. ** buf: Contains tag's response. ** bufLen: Length of buffer. -** +** ** Returns: None ** *******************************************************************************/ @@ -819,7 +820,7 @@ void nativeNfcTag_doTranseiveStatus (uint8_t* buf, uint32_t bufLen) ** o: Java object. ** raw: Not used. ** statusTargetLost: Whether tag responds or times out. -** +** ** Returns: Response from tag. ** *******************************************************************************/ @@ -828,7 +829,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da ALOGD ("%s: enter; raw=%u; timeout = %d", __FUNCTION__, raw, gGeneralTransceiveTimeout); bool fNeedToSwitchBack = false; nfc_jni_native_data *nat = getNative (0, 0); - bool waitOk = false; + bool waitOk = false; uint8_t *buf = NULL; uint32_t bufLen = 0; jint *targetLost = NULL; @@ -846,7 +847,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da return NULL; } - NfcTag& natTag = NfcTag::getInstance (); + NfcTag& natTag = NfcTag::getInstance (); if (natTag.mNumTechList >= 2 && natTag.mTechList[0] == TARGET_TYPE_ISO14443_3A) { if (natTag.mTechList[1] == TARGET_TYPE_MIFARE_CLASSIC) @@ -902,7 +903,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da waitOk = sTransceiveEvent.wait (gGeneralTransceiveTimeout); } - if (waitOk == false) //if timeout occured + if (waitOk == false) //if timeout occured { ALOGE ("%s: wait response timeout", __FUNCTION__); if (targetLost) @@ -917,7 +918,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da *targetLost = 1; //causes NFC service to throw TagLostException break; } - + ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen); if (sTransceiveDataLen) { @@ -946,7 +947,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da // this timer proc will switch us back to ISO_DEP frame interface sSwitchBackTimer.set (1500, switchBackTimerProc); } - + ALOGD ("%s: exit", __FUNCTION__); return result; } @@ -961,7 +962,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da ** o: Java object. ** libnfcType: Type of tag represented by JNI. ** javaType: Not used. -** +** ** Returns: Type of tag represented by NFC Service. ** *******************************************************************************/ @@ -1010,7 +1011,7 @@ static jint nativeNfcTag_doGetNdefType (JNIEnv *e, jobject o, jint libnfcType, j ** maxSize: Maximum size of NDEF message. ** currentSize: Current size of NDEF message. ** flags: Indicate various states. -** +** ** Returns: None ** *******************************************************************************/ @@ -1089,7 +1090,7 @@ void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint3 ** e: JVM environment. ** o: Java object. ** ndefInfo: NDEF info. -** +** ** Returns: Status code. ** *******************************************************************************/ @@ -1185,7 +1186,7 @@ TheEnd: ** e: JVM environment. ** o: Java object. ** ndefInfo: NDEF info. -** +** ** Returns: True if tag contains a NDEF message. ** *******************************************************************************/ @@ -1204,7 +1205,7 @@ static bool nativeNfcTag_doCheckNdef_z (JNIEnv *e, jobject o, jintArray ndefInfo ** Function: nativeNfcTag_resetPresenceCheck ** ** Description: Reset variables related to presence-check. -** +** ** Returns: None ** *******************************************************************************/ @@ -1220,7 +1221,7 @@ void nativeNfcTag_resetPresenceCheck () ** ** Description: Receive the result of presence-check. ** status: Result of presence-check. -** +** ** Returns: None ** *******************************************************************************/ @@ -1306,7 +1307,7 @@ static jboolean nativeNfcTag_doPresenceCheck (JNIEnv *e, jobject o) ** uidBytes: Tag's unique ID. ** pollBytes: Data from activation. ** actBytes: Data from activation. -** +** ** Returns: True if formattable. ** *******************************************************************************/ @@ -1340,7 +1341,7 @@ static jboolean nativeNfcTag_doIsNdefFormatable (JNIEnv *e, ** o: Java object. ** pollBytes: Data from activation. ** actBytes: Data from activation. -** +** ** Returns: True if formattable. ** *******************************************************************************/ @@ -1396,7 +1397,7 @@ static jboolean nativeNfcTag_doNdefFormat (JNIEnv *e, jobject o, jbyteArray key) ** Description: Receive the result of making a tag read-only. Called by the ** NFA_SET_TAG_RO_EVT. ** status: Status of the operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -1420,7 +1421,7 @@ void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status) ** e: JVM environment. ** o: Java object. ** key: Key to access the tag. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1439,7 +1440,7 @@ static jboolean nativeNfcTag_doMakeReadonly (JNIEnv *e, jobject o, jbyteArray ke } sMakeReadonlyWaitingForComplete = JNI_TRUE; - + // Hard-lock the tag (cannot be reverted) status = NFA_RwSetTagReadOnly(TRUE); @@ -1478,7 +1479,7 @@ TheEnd: ** ** Description: Register a callback to receive NDEF message from the tag ** from the NFA_NDEF_DATA_EVT. -** +** ** Returns: None ** *******************************************************************************/ @@ -1497,7 +1498,7 @@ void nativeNfcTag_registerNdefTypeHandler () ** Function: nativeNfcTag_deregisterNdefTypeHandler ** ** Description: No longer need to receive NDEF message from the tag. -** +** ** Returns: None ** *******************************************************************************/ @@ -1511,7 +1512,7 @@ void nativeNfcTag_deregisterNdefTypeHandler () /***************************************************************************** ** -** JNI functions for Android 4.0.3 +** JNI functions for Android 4.0.3 ** *****************************************************************************/ static JNINativeMethod gMethods[] = @@ -1538,7 +1539,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp index 16552a7..2f06b96 100644 --- a/nci/jni/NativeP2pDevice.cpp +++ b/nci/jni/NativeP2pDevice.cpp @@ -15,13 +15,14 @@ * limitations under the License. */ +#include "OverrideLog.h" #include "NfcJniUtil.h" namespace android { - + extern char* gNativeP2pDeviceClassName; @@ -81,7 +82,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp index 09091ed..55bece8 100755 --- a/nci/jni/NativeSecureElement.cpp +++ b/nci/jni/NativeSecureElement.cpp @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "NfcJniUtil.h" +#include "OverrideLog.h" #include "SecureElement.h" #include "nfa_brcm_api.h" @@ -22,7 +22,7 @@ namespace android { - + extern void com_android_nfc_NfcManager_disableDiscovery (JNIEnv* e, jobject o); extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode); extern char* gNativeNfcSecureElementClassName; @@ -36,7 +36,7 @@ extern int gGeneralTransceiveTimeout; ** Description: Connect to the secure element. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Handle of secure element. 0 is failure. ** *******************************************************************************/ @@ -60,7 +60,7 @@ static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, job else SecureElement::getInstance().deactivate (0); } - + TheEnd: ALOGD("%s: exit; return handle=0x%X", __FUNCTION__, secElemHandle); return secElemHandle; @@ -75,7 +75,7 @@ TheEnd: ** e: JVM environment. ** o: Java object. ** handle: Handle of secure element. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -85,7 +85,7 @@ static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIE bool stat = false; stat = SecureElement::getInstance().disconnectEE (handle); - + //if controller is not routing AND there is no pipe connected, //then turn off the sec elem if (! SecureElement::getInstance().isBusy()) @@ -105,7 +105,7 @@ static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIE ** o: Java object. ** handle: Secure element's handle. ** data: Data to send. -** +** ** Returns: Buffer of received data. ** *******************************************************************************/ @@ -145,7 +145,7 @@ static jbyteArray nativeNfcSecureElement_doTransceive (JNIEnv* e, jobject o, jin ** e: JVM environment. ** o: Java object. ** handle: Handle of secure element. -** +** ** Returns: Secure element's unique ID. ** *******************************************************************************/ @@ -169,7 +169,7 @@ static jbyteArray nativeNfcSecureElement_doGetUid (JNIEnv* e, jobject o, jint ha ** e: JVM environment. ** o: Java object. ** handle: Handle of secure element. -** +** ** Returns: Array of technologies. ** *******************************************************************************/ @@ -206,7 +206,7 @@ static JNINativeMethod gMethods[] = ** ** Description: Regisgter JNI functions with Java Virtual Machine. ** e: Environment of JVM. -** +** ** Returns: Status of registration. ** *******************************************************************************/ diff --git a/nci/jni/NfcJniUtil.cpp b/nci/jni/NfcJniUtil.cpp index d989188..7619f30 100755 --- a/nci/jni/NfcJniUtil.cpp +++ b/nci/jni/NfcJniUtil.cpp @@ -25,7 +25,7 @@ ** Description: Register all JNI functions with Java Virtual Machine. ** jvm: Java Virtual Machine. ** reserved: Not used. -** +** ** Returns: JNI version. ** *******************************************************************************/ @@ -65,8 +65,8 @@ namespace android ** ** Function: nfc_jni_cache_object ** -** Description: -** +** Description: +** ** Returns: Status code. ** *******************************************************************************/ @@ -75,14 +75,14 @@ int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj) jclass cls = NULL; jobject obj = NULL; jmethodID ctor = 0; - + cls = e->FindClass (className); if(cls == NULL) { ALOGE ("%s: find class error", __FUNCTION__); return -1; } - + ctor = e->GetMethodID (cls, "", "()V"); obj = e->NewObject (cls, ctor); if (obj == NULL) @@ -90,7 +90,7 @@ int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj) ALOGE ("%s: create object error", __FUNCTION__); return -1; } - + *cachedObj = e->NewGlobalRef (obj); if (*cachedObj == NULL) { @@ -110,7 +110,7 @@ int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj) ** Description: Get the value of "mHandle" member variable. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Value of mHandle. ** *******************************************************************************/ @@ -118,7 +118,7 @@ int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o) { jclass c = NULL; jfieldID f = 0; - + c = e->GetObjectClass (o); f = e->GetFieldID (c, "mHandle", "I"); return e->GetIntField (o, f); @@ -132,7 +132,7 @@ int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o) ** Description: Get the value of "mNative" member variable. ** e: JVM environment. ** o: Java object. -** +** ** Returns: Pointer to the value of mNative. ** *******************************************************************************/ diff --git a/nci/jni/NfcJniUtil.h b/nci/jni/NfcJniUtil.h index 18e75de..90f2cab 100755 --- a/nci/jni/NfcJniUtil.h +++ b/nci/jni/NfcJniUtil.h @@ -21,12 +21,7 @@ #include #include #include -extern "C" -{ - #include - #include -} -#include // for property_get +#include /* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */ @@ -48,10 +43,10 @@ extern "C" #define PROPERTY_LLCP_WKS 2 #define PROPERTY_LLCP_OPT 3 #define PROPERTY_NFC_DISCOVERY_A 4 -#define PROPERTY_NFC_DISCOVERY_B 5 +#define PROPERTY_NFC_DISCOVERY_B 5 #define PROPERTY_NFC_DISCOVERY_F 6 #define PROPERTY_NFC_DISCOVERY_15693 7 -#define PROPERTY_NFC_DISCOVERY_NCFIP 8 +#define PROPERTY_NFC_DISCOVERY_NCFIP 8 /* Error codes */ @@ -119,7 +114,7 @@ struct nfc_jni_native_data /* Secure Element selected */ int seId; - + /* LLCP params */ int lto; int miu; @@ -156,4 +151,3 @@ namespace android int register_com_android_nfc_NativeLlcpSocket (JNIEnv *e); int register_com_android_nfc_NativeNfcSecureElement (JNIEnv *e); } // namespace android - diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp index c135014..ebec941 100755 --- a/nci/jni/NfcTag.cpp +++ b/nci/jni/NfcTag.cpp @@ -8,7 +8,7 @@ ** Proprietary and confidential. ** *****************************************************************************/ - +#include "OverrideLog.h" #include "NfcTag.h" extern "C" { @@ -28,7 +28,7 @@ namespace android ** Function: NfcTag ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ @@ -44,7 +44,7 @@ NfcTag::NfcTag () memset (mTechHandles, 0, sizeof(mTechHandles)); memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); memset (mTechParams, 0, sizeof(mTechParams)); - mLastKovioUidLen = 0; + mLastKovioUidLen = 0; memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN); } @@ -54,7 +54,7 @@ NfcTag::NfcTag () ** Function: getInstance ** ** Description: Get a reference to the singleton NfcTag object. -** +** ** Returns: Reference to NfcTag object. ** *******************************************************************************/ @@ -71,7 +71,7 @@ NfcTag& NfcTag::getInstance () ** ** Description: Reset member variables. ** native: Native data. -** +** ** Returns: None ** *******************************************************************************/ @@ -89,10 +89,10 @@ void NfcTag::initialize (nfc_jni_native_data* native) /******************************************************************************* ** -** Function: abort +** Function: abort ** ** Description: Unblock all operations. -** +** ** Returns: None ** *******************************************************************************/ @@ -108,7 +108,7 @@ void NfcTag::abort () ** Function: isActivated ** ** Description: Is tag activated? -** +** ** Returns: True if tag is activated. ** *******************************************************************************/ @@ -123,7 +123,7 @@ bool NfcTag::isActivated () ** Function: getProtocol ** ** Description: Get the protocol of the current tag. -** +** ** Returns: Protocol number. ** *******************************************************************************/ @@ -249,8 +249,8 @@ void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData) { // need to look at first byte of uid to find manuf. tNFC_RF_TECH_PARAMS tech_params; - memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); - + memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + if ((tech_params.param.pa.nfcid1[0] == 0x04 && rfDetail.rf_tech_param.param.pa.sel_rsp == 0) || rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 || rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08) @@ -260,10 +260,10 @@ void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData) mTechHandles [mNumTechList] = rfDetail.rf_disc_id; mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; //save the stack's data structure for interpretation later - memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0) mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API - else + else mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API } } @@ -436,11 +436,11 @@ TheEnd: ** ** Function: createNativeNfcTag ** -** Description: Create a brand new Java NativeNfcTag object; +** Description: Create a brand new Java NativeNfcTag object; ** fill the objects's member variables with data; ** notify NFC service; ** activationData: data from activation. -** +** ** Returns: None ** *******************************************************************************/ @@ -936,7 +936,7 @@ void NfcTag::fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, t ** Function: isP2pDiscovered ** ** Description: Does the peer support P2P? -** +** ** Returns: True if the peer supports P2P. ** *******************************************************************************/ @@ -965,7 +965,7 @@ bool NfcTag::isP2pDiscovered () ** Function: selectP2p ** ** Description: Select the preferred P2P technology if there is a choice. -** +** ** Returns: None ** *******************************************************************************/ @@ -973,7 +973,7 @@ void NfcTag::selectP2p() { static const char fn [] = "NfcTag::selectP2p"; UINT8 rfDiscoveryId = 0; - + for (int i = 0; i < mNumTechList; i++) { //if remote device does not support P2P, just skip it @@ -1014,8 +1014,8 @@ void NfcTag::selectP2p() ** ** Function: resetTechnologies ** -** Description: Clear all data related to the technology, protocol of the tag. -** +** Description: Clear all data related to the technology, protocol of the tag. +** ** Returns: None ** *******************************************************************************/ @@ -1036,7 +1036,7 @@ void NfcTag::resetTechnologies () ** Function: selectFirstTag ** ** Description: When multiple tags are discovered, just select the first one to activate. -** +** ** Returns: None ** *******************************************************************************/ @@ -1067,7 +1067,7 @@ void NfcTag::selectFirstTag () ** Function: getT1tMaxMessageSize ** ** Description: Get the maximum size (octet) that a T1T can store. -** +** ** Returns: Maximum size in octets. ** *******************************************************************************/ @@ -1090,7 +1090,7 @@ int NfcTag::getT1tMaxMessageSize () ** ** Description: Calculate type-1 tag's max message size based on header ROM bytes. ** activate: reference to activation data. -** +** ** Returns: None ** *******************************************************************************/ @@ -1127,7 +1127,7 @@ void NfcTag::calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate) ** Function: isMifareUltralight ** ** Description: Whether the currently activated tag is Mifare Ultralight. -** +** ** Returns: True if tag is Mifare Ultralight. ** *******************************************************************************/ @@ -1176,7 +1176,7 @@ bool NfcTag::isMifareUltralight () ** Description: Handle connection-related events. ** event: event code. ** data: pointer to event data. -** +** ** Returns: None ** *******************************************************************************/ diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h index 2b17553..a692ddd 100755 --- a/nci/jni/NfcTag.h +++ b/nci/jni/NfcTag.h @@ -32,7 +32,7 @@ public: ** Function: NfcTag ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -44,7 +44,7 @@ public: ** Function: getInstance ** ** Description: Get a reference to the singleton NfcTag object. - ** + ** ** Returns: Reference to NfcTag object. ** *******************************************************************************/ @@ -65,10 +65,10 @@ public: /******************************************************************************* ** - ** Function: abort + ** Function: abort ** ** Description: Unblock all operations. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -82,7 +82,7 @@ public: ** Description: Handle connection-related events. ** event: event code. ** data: pointer to event data. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -94,7 +94,7 @@ public: ** Function: isActivated ** ** Description: Is tag activated? - ** + ** ** Returns: True if tag is activated. ** *******************************************************************************/ @@ -106,7 +106,7 @@ public: ** Function: getProtocol ** ** Description: Get the protocol of the current tag. - ** + ** ** Returns: Protocol number. ** *******************************************************************************/ @@ -118,7 +118,7 @@ public: ** Function: isP2pDiscovered ** ** Description: Does the peer support P2P? - ** + ** ** Returns: True if the peer supports P2P. ** *******************************************************************************/ @@ -130,7 +130,7 @@ public: ** Function: selectP2p ** ** Description: Select the preferred P2P technology if there is a choice. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -142,7 +142,7 @@ public: ** Function: selectFirstTag ** ** Description: When multiple tags are discovered, just select the first one to activate. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -154,7 +154,7 @@ public: ** Function: getT1tMaxMessageSize ** ** Description: Get the maximum size (octet) that a T1T can store. - ** + ** ** Returns: Maximum size in octets. ** *******************************************************************************/ @@ -166,7 +166,7 @@ public: ** Function: isMifareUltralight ** ** Description: Whether the currently activated tag is Mifare Ultralight. - ** + ** ** Returns: True if tag is Mifare Ultralight. ** *******************************************************************************/ @@ -174,7 +174,7 @@ public: private: nfc_jni_native_data* mNativeData; - bool mIsActivated; + bool mIsActivated; tNFC_PROTOCOL mProtocol; int mtT1tMaxMessageSize; //T1T max NDEF message size tNFA_STATUS mReadCompletedStatus; @@ -232,11 +232,11 @@ private: ** ** Function: createNativeNfcTag ** - ** Description: Create a brand new Java NativeNfcTag object; + ** Description: Create a brand new Java NativeNfcTag object; ** fill the objects's member variables with data; ** notify NFC service; ** activationData: data from activation. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -334,8 +334,8 @@ private: ** ** Function: resetTechnologies ** - ** Description: Clear all data related to the technology, protocol of the tag. - ** + ** Description: Clear all data related to the technology, protocol of the tag. + ** ** Returns: None ** *******************************************************************************/ @@ -348,7 +348,7 @@ private: ** ** Description: Calculate type-1 tag's max message size based on header ROM bytes. ** activate: reference to activation data. - ** + ** ** Returns: None ** *******************************************************************************/ diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index da3dbad..1272bf9 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -8,6 +8,7 @@ ** Proprietary and confidential. ** *****************************************************************************/ +#include "OverrideLog.h" #include "PeerToPeer.h" #include "NfcJniUtil.h" #include "llcp_defs.h" @@ -32,16 +33,16 @@ const std::string PeerToPeer::sNppServiceName ("com.android.npp"); ** Function: PeerToPeer ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ PeerToPeer::PeerToPeer () : mRemoteWKS (0), mIsP2pListening (false), - mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A - | NFA_TECHNOLOGY_MASK_F - | NFA_TECHNOLOGY_MASK_A_ACTIVE + mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A + | NFA_TECHNOLOGY_MASK_F + | NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE), mJniHandleSendingNppViaSnep (0), mSnepRegHandle (NFA_HANDLE_INVALID), @@ -50,14 +51,11 @@ PeerToPeer::PeerToPeer () mNppTotalLen (0), mNppReadSoFar (0), mNdefTypeHandlerHandle (NFA_HANDLE_INVALID), - mAppLogLevel (1), mJniVersion (403) { unsigned long num = 0; memset (mServers, 0, sizeof(mServers)); memset (mClients, 0, sizeof(mClients)); - if (GetNumValue ("APPL_TRACE_LEVEL", &num, sizeof (num))) - mAppLogLevel = num; } @@ -66,7 +64,7 @@ PeerToPeer::PeerToPeer () ** Function: ~PeerToPeer ** ** Description: Free all resources. -** +** ** Returns: None ** *******************************************************************************/ @@ -80,7 +78,7 @@ PeerToPeer::~PeerToPeer () ** Function: getInstance ** ** Description: Get the singleton PeerToPeer object. -** +** ** Returns: Singleton PeerToPeer object. ** *******************************************************************************/ @@ -96,7 +94,7 @@ PeerToPeer& PeerToPeer::getInstance () ** ** Description: Initialize member variables. ** jniVersion: JNI version. -** +** ** Returns: None ** *******************************************************************************/ @@ -118,7 +116,7 @@ void PeerToPeer::initialize (long jniVersion) ** ** Description: Find a PeerToPeer object by connection handle. ** nfaP2pServerHandle: Connectin handle. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -144,7 +142,7 @@ P2pServer *PeerToPeer::findServer (tNFA_HANDLE nfaP2pServerHandle) ** ** Description: Find a PeerToPeer object by connection handle. ** serviceName: service name. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -170,7 +168,7 @@ P2pServer *PeerToPeer::findServer (tBRCM_JNI_HANDLE jniHandle) ** ** Description: Find a PeerToPeer object by service name ** serviceName: service name. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -194,7 +192,7 @@ P2pServer *PeerToPeer::findServer (const char *serviceName) ** Description: Let a server start listening for peer's connection request. ** jniHandle: Connection handle. ** serviceName: Server's service name. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -206,7 +204,7 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service P2pServer *pSrv = NULL; UINT8 serverSap = NFA_P2P_ANY_SAP; - // Check if already registered + // Check if already registered if ((pSrv = findServer(serviceName)) != NULL) { ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle); @@ -247,10 +245,10 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) ************************/ - stat = NFA_P2pSetLLCPConfig (LLCP_MIU, + stat = NFA_P2pSetLLCPConfig (LLCP_MIU, LLCP_OPT_VALUE, - LLCP_WAITING_TIME, - LLCP_LTO_VALUE, + LLCP_WAITING_TIME, + LLCP_LTO_VALUE, 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator 0, //use 0 for infinite timeout for symmetry procedure when acting as target LLCP_DELAY_RESP_TIME, @@ -294,7 +292,7 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service ** ** Description: Free resources related to a server. ** jniHandle: Connection handle. -** +** ** Returns: None ** *******************************************************************************/ @@ -325,7 +323,7 @@ void PeerToPeer::removeServer (tBRCM_JNI_HANDLE jniHandle) ** Description: Receive LLLCP-activated event from stack. ** nat: JVM-related data. ** activated: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -354,31 +352,31 @@ void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIV ALOGE ("%s: jni env is null", fn); return; } - + ALOGD ("%s: get object class", fn); tag_cls = e->GetObjectClass (nat->cached_P2pDevice); if (e->ExceptionCheck()) { e->ExceptionClear(); - ALOGE ("%s: fail get p2p device", fn); + ALOGE ("%s: fail get p2p device", fn); goto TheEnd; - } + } ALOGD ("%s: instantiate", fn); /* New target instance */ ctor = e->GetMethodID (tag_cls, "", "()V"); tag = e->NewObject (tag_cls, ctor); - + /* Set P2P Target mode */ - f = e->GetFieldID (tag_cls, "mMode", "I"); - + f = e->GetFieldID (tag_cls, "mMode", "I"); + if (activated.is_initiator == TRUE) { ALOGD ("%s: p2p initiator", fn); e->SetIntField (tag, f, (jint) MODE_P2P_INITIATOR); } else - { + { ALOGD ("%s: p2p target", fn); e->SetIntField (tag, f, (jint) MODE_P2P_TARGET); } @@ -401,7 +399,7 @@ void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIV { e->ExceptionClear(); ALOGE ("%s: fail notify", fn); - } + } e->DeleteLocalRef (tag); @@ -418,7 +416,7 @@ TheEnd: ** Description: Receive LLLCP-deactivated event from stack. ** nat: JVM-related data. ** deactivated: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -442,14 +440,14 @@ void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEA { e->ExceptionClear(); ALOGE ("%s: fail notify", fn); - } + } nat->vm->DetachCurrentThread (); - + //PeerToPeer no longer needs to handle NDEF data event NFA_DeregisterNDefTypeHandler (mNdefTypeHandlerHandle); mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; - + //let the tag-reading code handle NDEF data event android::nativeNfcTag_registerNdefTypeHandler (); ALOGD ("%s: exit", fn); @@ -465,7 +463,7 @@ void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEA ** connJniHandle: Connection handle. ** maxInfoUnit: Maximum information unit. ** recvWindow: Receive window size. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -555,7 +553,7 @@ bool PeerToPeer::accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE conn ** Function: deregisterServer ** ** Description: Stop a P2pServer from listening for peer. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -597,7 +595,7 @@ bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) ** jniHandle: Connection handle. ** miu: Maximum information unit. ** rw: Receive window size. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -652,7 +650,7 @@ bool PeerToPeer::createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) ** ** Description: Free resources related to a connection. ** jniHandle: Connection handle. -** +** ** Returns: None ** *******************************************************************************/ @@ -718,7 +716,7 @@ void PeerToPeer::removeConn(tBRCM_JNI_HANDLE jniHandle) ** Description: Estabish a connection-oriented connection to a peer. ** jniHandle: Connection handle. ** serviceName: Peer's service name. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -778,7 +776,7 @@ bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* se ** Description: Estabish a connection-oriented connection to a peer. ** jniHandle: Connection handle. ** destinationSap: Peer's service access point. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -800,7 +798,7 @@ bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinat ** jniHandle: Connection handle. ** serviceName: Peer's service name. ** destinationSap: Peer's service access point. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -858,7 +856,7 @@ bool PeerToPeer::createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* ser ** ** Description: Find a PeerToPeer object with a client connection handle. ** nfaConnHandle: Connection handle. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -879,7 +877,7 @@ P2pClient *PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) ** ** Description: Find a PeerToPeer object with a client connection handle. ** jniHandle: Connection handle. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -900,7 +898,7 @@ P2pClient *PeerToPeer::findClient (tBRCM_JNI_HANDLE jniHandle) ** ** Description: Find a PeerToPeer object with a client connection handle. ** nfaConnHandle: Connection handle. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -921,7 +919,7 @@ P2pClient *PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) ** ** Description: Find a PeerToPeer object with a connection handle. ** nfaConnHandle: Connection handle. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -962,7 +960,7 @@ NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) ** ** Description: Find a PeerToPeer object with a connection handle. ** jniHandle: Connection handle. -** +** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -1005,7 +1003,7 @@ NfaConn *PeerToPeer::findConnection (tBRCM_JNI_HANDLE jniHandle) ** jniHandle: Handle of connection. ** buffer: Buffer of data. ** bufferLen: Length of data. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1021,7 +1019,7 @@ bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferL return (false); } - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X mJniHandleSendingNppViaSnep: %u", + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X mJniHandleSendingNppViaSnep: %u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, mJniHandleSendingNppViaSnep); // Is this a SNEP fake-out @@ -1044,7 +1042,7 @@ bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferL } if (nfaStat == NFA_STATUS_OK) - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle); else ALOGE ("%s: Data not sent; JNI handle: %u NFA Handle: 0x%04x error: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle, nfaStat); @@ -1061,7 +1059,7 @@ bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferL ** jniHandle: Handle of connection. ** buffer: Buffer of data. ** dataLen: Length of data. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1078,7 +1076,7 @@ bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 return (false); } - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u mSnepNdefMsgLen: %lu mSnepNdefBufLen: %lu dataLen: %d", + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u mSnepNdefMsgLen: %lu mSnepNdefBufLen: %lu dataLen: %d", fn, jniHandle, pClient->mSnepNdefMsgLen, pClient->mSnepNdefBufLen, dataLen); if (pClient->mSnepNdefMsgLen == 0) @@ -1146,14 +1144,14 @@ bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 ** buffer: Buffer to store data. ** bufferLen: Max length of buffer. ** actualLen: Actual length received. -** +** ** Returns: True if ok. ** *******************************************************************************/ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) { static const char fn [] = "PeerToPeer::receive"; - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); NfaConn *pConn = NULL; tNFA_STATUS stat = NFA_STATUS_FAILED; UINT32 actualDataLen2 = 0; @@ -1169,7 +1167,7 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff return (false); } - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) { @@ -1180,14 +1178,14 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff retVal = true; break; } - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); { SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.wait(); } } //while - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen); return retVal; } @@ -1200,7 +1198,7 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff ** buffer: Buffer of data to send. ** bufferLen: Length of data in buffer. ** actualLen: Actual length sent. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1208,7 +1206,7 @@ bool PeerToPeer::feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actua { static const char fn [] = "PeerToPeer::feedNppFromSnep"; - ALOGD_IF ((mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: mNppTotalLen: %lu mNppReadSoFar: %lu bufferLen: %u", + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: mNppTotalLen: %lu mNppReadSoFar: %lu bufferLen: %u", fn, mNppTotalLen, mNppReadSoFar, bufferLen); if (bufferLen > (mNppTotalLen - mNppReadSoFar)) @@ -1236,7 +1234,7 @@ bool PeerToPeer::feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actua ** ** Description: Disconnect a connection-oriented connection with peer. ** jniHandle: Handle of connection. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1299,7 +1297,7 @@ bool PeerToPeer::disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle) ** ** Description: Get peer's max information unit. ** jniHandle: Handle of the connection. -** +** ** Returns: Peer's max information unit. ** *******************************************************************************/ @@ -1324,7 +1322,7 @@ UINT16 PeerToPeer::getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle) ** ** Description: Get peer's receive window size. ** jniHandle: Handle of the connection. -** +** ** Returns: Peer's receive window size. ** *******************************************************************************/ @@ -1362,7 +1360,7 @@ void PeerToPeer::setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask) { ** ** Description: Start/stop polling/listening to peer that supports P2P. ** isEnable: Is enable polling/listening? -** +** ** Returns: None ** *******************************************************************************/ @@ -1382,7 +1380,7 @@ void PeerToPeer::enableP2pListening (bool isEnable) mSetTechEvent.wait (); mIsP2pListening = true; } - else + else ALOGE ("%s: fail enable listen; error=0x%X", fn, nfaStat); } else if ( (isEnable == false) && (mIsP2pListening == true) ) @@ -1396,7 +1394,7 @@ void PeerToPeer::enableP2pListening (bool isEnable) } else ALOGE ("%s: fail disable listen; error=0x%X", fn, nfaStat); - } + } ALOGD ("%s: exit; mIsP2pListening: %u", fn, mIsP2pListening); } @@ -1407,7 +1405,7 @@ void PeerToPeer::enableP2pListening (bool isEnable) ** ** Description: Handle events related to turning NFC on/off by the user. ** isOn: Is NFC turning on? -** +** ** Returns: None ** *******************************************************************************/ @@ -1433,16 +1431,16 @@ void PeerToPeer::handleNfcOnOff (bool isOn) SyncEventGuard guard (mSnepDefaultServerStartStopEvent); stat = NFA_SnepStartDefaultServer (snepClientCallback); if (stat == NFA_STATUS_OK) - mSnepDefaultServerStartStopEvent.wait (); //wait for NFA_SNEP_DEFAULT_SERVER_STARTED_EVT + mSnepDefaultServerStartStopEvent.wait (); //wait for NFA_SNEP_DEFAULT_SERVER_STARTED_EVT else ALOGE ("%s: fail start snep server; error=0x%X", fn, stat); } - { + { SyncEventGuard guard (mSnepRegisterEvent); stat = NFA_SnepRegisterClient (snepClientCallback); if (stat == NFA_STATUS_OK) - mSnepRegisterEvent.wait (); //wait for NFA_SNEP_REG_EVT + mSnepRegisterEvent.wait (); //wait for NFA_SNEP_REG_EVT else ALOGE ("%s: fail register snep client; error=0x%X", fn, stat); } @@ -1520,8 +1518,8 @@ void PeerToPeer::handleNfcOnOff (bool isOn) ** ** Description: Receive LLCP-related events from the stack. ** p2pEvent: Event code. -** eventData: Event data. -** +** eventData: Event data. +** ** Returns: None ** *******************************************************************************/ @@ -1531,7 +1529,7 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev P2pServer *pSrv = NULL; NfaConn *pConn = NULL; - ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent); switch (p2pEvent) { @@ -1554,7 +1552,7 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev case NFA_P2P_ACTIVATED_EVT: //remote device has activated ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); break; - + case NFA_P2P_DEACTIVATED_EVT: ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); break; @@ -1632,7 +1630,7 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev } else { - ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, eventData->data.handle, eventData->data.remote_sap); SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.notifyOne(); @@ -1659,7 +1657,7 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); break; } - ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn); } @@ -1669,8 +1667,8 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev ** ** Description: Receive LLCP-related events from the stack. ** p2pEvent: Event code. -** eventData: Event data. -** +** eventData: Event data. +** ** Returns: None ** *******************************************************************************/ @@ -1680,7 +1678,7 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev NfaConn *pConn = NULL; P2pClient *pClient = NULL; - ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent); + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent); switch (p2pEvent) { @@ -1784,13 +1782,13 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev } else { - ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, eventData->data.handle, eventData->data.remote_sap); SyncEventGuard guard (pConn->mReadEvent); pConn->mReadEvent.notifyOne(); } break; - + case NFA_P2P_CONGEST_EVT: // Look for the connection block if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) @@ -1799,7 +1797,7 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev } else { - ALOGD_IF ((sP2p.mAppLogLevel>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, eventData->congest.handle, eventData->congest.is_congested); SyncEventGuard guard (pConn->mCongEvent); @@ -1821,7 +1819,7 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev ** Description: Receive SNEP-related events from the stack. ** snepEvent: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -1897,7 +1895,7 @@ void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA pClient->mSnepEvent.notifyOne(); } break; - + case NFA_SNEP_DEFAULT_SERVER_STARTED_EVT: { ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STARTED_EVT", fn); @@ -1929,7 +1927,7 @@ void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA ** Description: Receive NDEF-related events from the stack. ** ndefEvent: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -1999,27 +1997,12 @@ void PeerToPeer::ndefTypeCallback (tNFA_NDEF_EVT ndefEvent, tNFA_NDEF_EVT_DATA * /******************************************************************************* ** -** Function: getLogLevel -** -** Description: Get the diagnostic logging level. -** -** Returns: Log level; 0=no logging; 1=error only; 5=debug -** -*******************************************************************************/ -UINT32 PeerToPeer::getLogLevel () -{ - return mAppLogLevel; -} - - -/******************************************************************************* -** ** Function: connectionEventHandler ** ** Description: Receive events from the stack. ** event: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -2046,7 +2029,7 @@ void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventD ** Function: P2pServer ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ @@ -2064,7 +2047,7 @@ P2pServer::P2pServer() ** ** Description: Find a P2pServer that has the handle. ** nfaConnHandle: NFA connection handle. -** +** ** Returns: P2pServer object. ** *******************************************************************************/ @@ -2092,7 +2075,7 @@ NfaConn *P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) ** Function: P2pClient ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ @@ -2113,7 +2096,7 @@ P2pClient::P2pClient () ** Function: ~P2pClient ** ** Description: Free all resources. -** +** ** Returns: None ** *******************************************************************************/ @@ -2133,7 +2116,7 @@ P2pClient::~P2pClient () ** Function: NfaConn ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index e7fcbf8..b9c7b39 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -35,57 +35,57 @@ typedef unsigned int tBRCM_JNI_HANDLE; class PeerToPeer { public: - - + + /******************************************************************************* ** ** Function: PeerToPeer ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ PeerToPeer (); - - + + /******************************************************************************* ** ** Function: ~PeerToPeer ** ** Description: Free all resources. - ** + ** ** Returns: None ** *******************************************************************************/ ~PeerToPeer (); - + /******************************************************************************* ** ** Function: getInstance ** ** Description: Get the singleton PeerToPeer object. - ** + ** ** Returns: Singleton PeerToPeer object. ** *******************************************************************************/ static PeerToPeer& getInstance(); - - + + /******************************************************************************* ** ** Function: initialize ** ** Description: Initialize member variables. ** jniVersion: JNI version. - ** + ** ** Returns: None ** *******************************************************************************/ void initialize (long jniVersion); - - + + /******************************************************************************* ** ** Function: llcpActivatedHandler @@ -93,13 +93,13 @@ public: ** Description: Receive LLLCP-activated event from stack. ** nat: JVM-related data. ** activated: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ void llcpActivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_ACTIVATED& activated); - - + + /******************************************************************************* ** ** Function: llcpDeactivatedHandler @@ -107,13 +107,13 @@ public: ** Description: Receive LLLCP-deactivated event from stack. ** nat: JVM-related data. ** deactivated: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ void llcpDeactivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_DEACTIVATED& deactivated); - - + + /******************************************************************************* ** ** Function: connectionEventHandler @@ -121,13 +121,13 @@ public: ** Description: Receive events from the stack. ** event: Event code. ** eventData: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData); - + /******************************************************************************* ** ** Function: registerServer @@ -135,25 +135,25 @@ public: ** Description: Let a server start listening for peer's connection request. ** jniHandle: Connection handle. ** serviceName: Server's service name. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool registerServer (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); - - + + /******************************************************************************* ** ** Function: deregisterServer ** ** Description: Stop a P2pServer from listening for peer. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool deregisterServer (tBRCM_JNI_HANDLE jniHandle); - - + + /******************************************************************************* ** ** Function: accept @@ -163,13 +163,13 @@ public: ** connJniHandle: Connection handle. ** maxInfoUnit: Maximum information unit. ** recvWindow: Receive window size. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow); - + /******************************************************************************* ** ** Function: createClient @@ -178,13 +178,13 @@ public: ** jniHandle: Connection handle. ** miu: Maximum information unit. ** rw: Receive window size. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw); - - + + /******************************************************************************* ** ** Function: connectConnOriented @@ -192,13 +192,13 @@ public: ** Description: Estabish a connection-oriented connection to a peer. ** jniHandle: Connection handle. ** serviceName: Peer's service name. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); - - + + /******************************************************************************* ** ** Function: connectConnOriented @@ -206,13 +206,13 @@ public: ** Description: Estabish a connection-oriented connection to a peer. ** jniHandle: Connection handle. ** destinationSap: Peer's service access point. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap); - - + + /******************************************************************************* ** ** Function: send @@ -221,13 +221,13 @@ public: ** jniHandle: Handle of connection. ** buffer: Buffer of data. ** bufferLen: Length of data. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool send (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen); - - + + /******************************************************************************* ** ** Function: receive @@ -237,7 +237,7 @@ public: ** buffer: Buffer to store data. ** bufferLen: Max length of buffer. ** actualLen: Actual length received. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -250,7 +250,7 @@ public: ** ** Description: Disconnect a connection-oriented connection with peer. ** jniHandle: Handle of connection. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -263,7 +263,7 @@ public: ** ** Description: Get peer's max information unit. ** jniHandle: Handle of the connection. - ** + ** ** Returns: Peer's max information unit. ** *******************************************************************************/ @@ -276,7 +276,7 @@ public: ** ** Description: Get peer's receive window size. ** jniHandle: Handle of the connection. - ** + ** ** Returns: Peer's receive window size. ** *******************************************************************************/ @@ -301,7 +301,7 @@ public: ** ** Description: Start/stop polling/listening to peer that supports P2P. ** isEnable: Is enable polling/listening? - ** + ** ** Returns: None ** *******************************************************************************/ @@ -314,24 +314,12 @@ public: ** ** Description: Handle events related to turning NFC on/off by the user. ** isOn: Is NFC turning on? - ** + ** ** Returns: None ** *******************************************************************************/ void handleNfcOnOff (bool isOn); - - /******************************************************************************* - ** - ** Function: getLogLevel - ** - ** Description: Get the diagnostic logging level. - ** - ** Returns: Log level; 0=no logging; 1=error only; 5=debug - ** - *******************************************************************************/ - UINT32 getLogLevel (); - private: static const int sMax = 10; static PeerToPeer sP2p; @@ -339,7 +327,7 @@ private: static const std::string sNppServiceName; UINT16 mRemoteWKS; // Peer's well known services bool mIsP2pListening; // If P2P listening is enabled or not - tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask + tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask tBRCM_JNI_HANDLE mJniHandleSendingNppViaSnep; tNFA_HANDLE mSnepRegHandle; tBRCM_JNI_HANDLE mRcvFakeNppJniHandle; @@ -347,7 +335,6 @@ private: UINT32 mNppTotalLen; UINT32 mNppReadSoFar; tNFA_HANDLE mNdefTypeHandlerHandle; - UINT32 mAppLogLevel; long mJniVersion; P2pServer *mServers [sMax]; @@ -356,36 +343,36 @@ private: SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer() SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient() Mutex mDisconnectMutex; // synchronize the disconnect operation - - + + /******************************************************************************* ** ** Function: nfaServerCallback ** ** Description: Receive LLCP-related events from the stack. ** p2pEvent: Event code. - ** eventData: Event data. - ** + ** eventData: Event data. + ** ** Returns: None ** *******************************************************************************/ static void nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); - - + + /******************************************************************************* ** ** Function: nfaClientCallback ** ** Description: Receive LLCP-related events from the stack. ** p2pEvent: Event code. - ** eventData: Event data. - ** + ** eventData: Event data. + ** ** Returns: None ** *******************************************************************************/ static void nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); - - + + /******************************************************************************* ** ** Function: snepClientCallback @@ -393,13 +380,13 @@ private: ** Description: Receive SNEP-related events from the stack. ** snepEvent: Event code. ** eventData: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ static void snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData); - - + + /******************************************************************************* ** ** Function: ndefTypeCallback @@ -407,20 +394,20 @@ private: ** Description: Receive NDEF-related events from the stack. ** ndefEvent: Event code. ** eventData: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ static void ndefTypeCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *evetnData); - + /******************************************************************************* ** ** Function: findServer ** ** Description: Find a PeerToPeer object by connection handle. ** nfaP2pServerHandle: Connectin handle. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -433,7 +420,7 @@ private: ** ** Description: Find a PeerToPeer object by connection handle. ** serviceName: service name. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -446,7 +433,7 @@ private: ** ** Description: Find a PeerToPeer object by service name ** serviceName: service name. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -459,7 +446,7 @@ private: ** ** Description: Free resources related to a server. ** jniHandle: Connection handle. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -472,7 +459,7 @@ private: ** ** Description: Free resources related to a connection. ** jniHandle: Connection handle. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -487,7 +474,7 @@ private: ** jniHandle: Connection handle. ** serviceName: Peer's service name. ** destinationSap: Peer's service access point. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -500,7 +487,7 @@ private: ** ** Description: Find a PeerToPeer object with a client connection handle. ** nfaConnHandle: Connection handle. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -513,7 +500,7 @@ private: ** ** Description: Find a PeerToPeer object with a client connection handle. ** jniHandle: Connection handle. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -526,7 +513,7 @@ private: ** ** Description: Find a PeerToPeer object with a client connection handle. ** nfaConnHandle: Connection handle. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -539,7 +526,7 @@ private: ** ** Description: Find a PeerToPeer object with a connection handle. ** nfaConnHandle: Connection handle. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -552,7 +539,7 @@ private: ** ** Description: Find a PeerToPeer object with a connection handle. ** jniHandle: Connection handle. - ** + ** ** Returns: PeerToPeer object. ** *******************************************************************************/ @@ -567,7 +554,7 @@ private: ** jniHandle: Handle of connection. ** buffer: Buffer of data. ** dataLen: Length of data. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -582,7 +569,7 @@ private: ** buffer: Buffer of data to send. ** bufferLen: Length of data in buffer. ** actualLen: Actual length sent. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -616,7 +603,7 @@ public: ** Function: NfaConn ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -640,13 +627,13 @@ public: SyncEvent mConnRequestEvent; // for accept() std::string mServiceName; NfaConn *mServerConn[MAX_NFA_CONNS_PER_SERVER]; - + /******************************************************************************* ** ** Function: P2pServer ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -659,7 +646,7 @@ public: ** ** Description: Find a P2pServer that has the handle. ** nfaConnHandle: NFA connection handle. - ** + ** ** Returns: P2pServer object. ** *******************************************************************************/ @@ -694,7 +681,7 @@ public: ** Function: P2pClient ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -706,7 +693,7 @@ public: ** Function: ~P2pClient ** ** Description: Free all resources. - ** + ** ** Returns: None ** *******************************************************************************/ diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp index e5faaae..ba1a96b 100755 --- a/nci/jni/PowerSwitch.cpp +++ b/nci/jni/PowerSwitch.cpp @@ -8,6 +8,7 @@ ** Proprietary and confidential. ** *****************************************************************************/ +#include "OverrideLog.h" #include "PowerSwitch.h" #include "NfcJniUtil.h" #include "config.h" @@ -28,7 +29,7 @@ PowerSwitch PowerSwitch::sPowerSwitch; ** Function: PowerSwitch ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ @@ -40,13 +41,13 @@ PowerSwitch::PowerSwitch () { } - + /******************************************************************************* ** ** Function: ~PowerSwitch ** ** Description: Release all resources. -** +** ** Returns: None ** *******************************************************************************/ @@ -60,7 +61,7 @@ PowerSwitch::~PowerSwitch () ** Function: getInstance ** ** Description: Get the singleton of this object. -** +** ** Returns: Reference to this object. ** *******************************************************************************/ @@ -75,7 +76,7 @@ PowerSwitch& PowerSwitch::getInstance () ** Function: initialize ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ @@ -93,12 +94,12 @@ void PowerSwitch::initialize (PowerLevel level) mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL; mCurrLevel = level; break; - + case UNKNOWN_LEVEL: mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN; mCurrLevel = level; break; - + default: ALOGE ("%s: not handled", fn); break; @@ -108,10 +109,10 @@ void PowerSwitch::initialize (PowerLevel level) /******************************************************************************* ** -** Function: getLevel +** Function: getLevel ** ** Description: Get the current power level of the controller. -** +** ** Returns: Power level. ** *******************************************************************************/ @@ -120,14 +121,14 @@ PowerSwitch::PowerLevel PowerSwitch::getLevel () return mCurrLevel; } - + /******************************************************************************* ** ** Function: setLevel ** ** Description: Set the controller's power level. ** level: power level. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -146,7 +147,7 @@ bool PowerSwitch::setLevel (PowerLevel newLevel) if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP) retval = setPowerOffSleepState (false); break; - + case LOW_POWER: case POWER_OFF: if (isPowerOffSleepFeatureEnabled()) @@ -157,7 +158,7 @@ bool PowerSwitch::setLevel (PowerLevel newLevel) retval = true; } break; - + default: ALOGE ("%s: not handled", fn); break; @@ -202,7 +203,7 @@ bool PowerSwitch::setScreenState(bool state) ** ** Description: Adjust controller's power-off-sleep state. ** sleep: whether to enter sleep state. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -245,12 +246,12 @@ bool PowerSwitch::setPowerOffSleepState (bool sleep) } else { - ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn, + ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn, deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } } - else //exit power-off-sleep state + else //exit power-off-sleep state { //make sure the current power state is OFF if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) @@ -264,7 +265,7 @@ bool PowerSwitch::setPowerOffSleepState (bool sleep) mPowerStateEvent.wait (); if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL) { - ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn, + ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn, deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } @@ -279,7 +280,7 @@ bool PowerSwitch::setPowerOffSleepState (bool sleep) } else { - ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn, + ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn, deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState); goto TheEnd; } @@ -296,9 +297,9 @@ TheEnd: ** ** Function: deviceMgtPowerStateToString ** -** Description: Decode power level to a string. +** Description: Decode power level to a string. ** deviceMgtPowerState: power level. -** +** ** Returns: Text representation of power level. ** *******************************************************************************/ @@ -322,7 +323,7 @@ const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState) ** ** Description: Decode power level to a string. ** level: power level. -** +** ** Returns: Text representation of power level. ** *******************************************************************************/ @@ -349,7 +350,7 @@ const char* PowerSwitch::powerLevelToString (PowerLevel level) ** Function: abort ** ** Description: Abort and unblock currrent operation. -** +** ** Returns: None ** *******************************************************************************/ @@ -369,7 +370,7 @@ void PowerSwitch::abort () ** Description: Callback function for the stack. ** event: event ID. ** eventData: event's data. -** +** ** Returns: None ** *******************************************************************************/ @@ -382,7 +383,7 @@ void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eve case NFA_DM_PWR_MODE_CHANGE_EVT: { tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode; - ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=%u; device mgt power mode=%s (%u)", fn, + ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=%u; device mgt power mode=%s (%u)", fn, power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode), power_mode.power_mode); SyncEventGuard guard (sPowerSwitch.mPowerStateEvent); if (power_mode.status == NFA_STATUS_OK) @@ -399,12 +400,12 @@ void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eve ** Function: isPowerOffSleepFeatureEnabled ** ** Description: Whether power-off-sleep feature is enabled in .conf file. -** +** ** Returns: True if feature is enabled. ** *******************************************************************************/ bool PowerSwitch::isPowerOffSleepFeatureEnabled () { - return mDesiredScreenOffPowerState == 0; + return mDesiredScreenOffPowerState == 0; } diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h index 09197f1..896133e 100755 --- a/nci/jni/PowerSwitch.h +++ b/nci/jni/PowerSwitch.h @@ -59,54 +59,54 @@ public: ** Function: PowerSwitch ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ PowerSwitch (); - - + + /******************************************************************************* ** ** Function: ~PowerSwitch ** ** Description: Release all resources. - ** + ** ** Returns: None ** *******************************************************************************/ ~PowerSwitch (); - - + + /******************************************************************************* ** ** Function: getInstance ** ** Description: Get the singleton of this object. - ** + ** ** Returns: Reference to this object. ** *******************************************************************************/ static PowerSwitch& getInstance (); - + /******************************************************************************* ** ** Function: initialize ** ** Description: Initialize member variables. - ** + ** ** Returns: None ** *******************************************************************************/ void initialize (PowerLevel level); - - + + /******************************************************************************* ** - ** Function: getLevel + ** Function: getLevel ** ** Description: Get the current power level of the controller. - ** + ** ** Returns: Power level. ** *******************************************************************************/ @@ -124,19 +124,19 @@ public: *******************************************************************************/ bool isScreenOn (); - + /******************************************************************************* ** ** Function: setLevel ** ** Description: Set the controller's power level. ** level: power level. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool setLevel (PowerLevel level); - + /******************************************************************************* ** ** Function: setScreenState @@ -154,13 +154,13 @@ public: ** Function: abort ** ** Description: Abort and unblock currrent operation. - ** + ** ** Returns: None ** *******************************************************************************/ void abort (); - - + + /******************************************************************************* ** ** Function: deviceManagementCallback @@ -168,19 +168,19 @@ public: ** Description: Callback function for the stack. ** event: event ID. ** eventData: event's data. - ** + ** ** Returns: None ** *******************************************************************************/ static void deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData); - + /******************************************************************************* ** ** Function: isPowerOffSleepFeatureEnabled ** ** Description: Whether power-off-sleep feature is enabled in .conf file. - ** + ** ** Returns: True if feature is enabled. ** *******************************************************************************/ @@ -194,41 +194,41 @@ private: static PowerSwitch sPowerSwitch; //singleton object static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown SyncEvent mPowerStateEvent; - - + + /******************************************************************************* ** ** Function: setPowerOffSleepState ** ** Description: Adjust controller's power-off-sleep state. ** sleep: whether to enter sleep state. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool setPowerOffSleepState (bool sleep); - - + + /******************************************************************************* ** ** Function: deviceMgtPowerStateToString ** - ** Description: Decode power level to a string. + ** Description: Decode power level to a string. ** deviceMgtPowerState: power level. - ** + ** ** Returns: Text representation of power level. ** *******************************************************************************/ const char* deviceMgtPowerStateToString (UINT8 deviceMgtPowerState); - - + + /******************************************************************************* ** ** Function: powerLevelToString ** ** Description: Decode power level to a string. ** level: power level. - ** + ** ** Returns: Text representation of power level. ** *******************************************************************************/ diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp index 6f6eff7..8985a90 100644 --- a/nci/jni/RouteDataSet.cpp +++ b/nci/jni/RouteDataSet.cpp @@ -8,7 +8,7 @@ ** Proprietary and confidential. ** *****************************************************************************/ - +#include "OverrideLog.h" #include "RouteDataSet.h" #include "libxml/xmlmemory.h" #include @@ -88,7 +88,7 @@ const char* RouteDataSet::sConfigFile = "/param/route.xml"; ** Function: ~RouteDataSet ** ** Description: Release all resources. -** +** ** Returns: None. ** *******************************************************************************/ @@ -103,7 +103,7 @@ RouteDataSet::~RouteDataSet () ** Function: initialize ** ** Description: Initialize resources. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -124,7 +124,7 @@ bool RouteDataSet::initialize () ** Function: deleteDatabase ** ** Description: Delete all routes stored in all databases. -** +** ** Returns: None. ** *******************************************************************************/ @@ -149,7 +149,7 @@ void RouteDataSet::deleteDatabase () ** Function: import ** ** Description: Import data from an XML file. Fill the databases. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -164,7 +164,7 @@ bool RouteDataSet::import () strFilename += sConfigFile; deleteDatabase (); - + doc = xmlParseFile (strFilename.c_str()); if (doc == NULL) { @@ -218,7 +218,7 @@ bool RouteDataSet::import () node1 = node1->next; } //loop through all elements in #include +#include "OverrideLog.h" #include "SecureElement.h" #include "config.h" #include "PowerSwitch.h" @@ -48,7 +49,7 @@ SecureElement SecureElement::sSecElem; ** Function: SecureElement ** ** Description: Initialize member variables. -** +** ** Returns: None ** *******************************************************************************/ @@ -61,7 +62,7 @@ SecureElement::SecureElement () mActualNumEe (0), mNumEePresent(0), mbNewEE (true), // by default we start w/thinking there are new EE - mNewPipeId (0), + mNewPipeId (0), mNewSourceGate (0), mActiveSeOverride(0), mCommandStatus (NFA_STATUS_OK), @@ -81,7 +82,7 @@ SecureElement::SecureElement () ** Function: ~SecureElement ** ** Description: Release all resources. -** +** ** Returns: None ** *******************************************************************************/ @@ -95,7 +96,7 @@ SecureElement::~SecureElement () ** Function: getInstance ** ** Description: Get the SecureElement singleton object. -** +** ** Returns: SecureElement object. ** *******************************************************************************/ @@ -128,7 +129,7 @@ void SecureElement::setActiveSeOverride(UINT8 activeSeOverride) ** ** Description: Initialize all member variables. ** native: Native data. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -143,12 +144,12 @@ bool SecureElement::initialize (nfc_jni_native_data* native) if (GetNumValue("NFA_HCI_DEFAULT_DEST_GATE", &num, sizeof(num))) mDestinationGate = num; - ALOGD ("%s: Default destination gate: %d", __FUNCTION__, mDestinationGate); + ALOGD ("%s: Default destination gate: %d", fn, mDestinationGate); // active SE, if not set active all SEs if (GetNumValue("ACTIVE_SE", &num, sizeof(num))) mActiveSeOverride = num; - ALOGD ("%s: Active SE override: %d", __FUNCTION__, mActiveSeOverride); + ALOGD ("%s: Active SE override: %d", fn, mActiveSeOverride); mActiveEeHandle = NFA_HANDLE_INVALID; mNfaHciHandle = NFA_HANDLE_INVALID; @@ -169,7 +170,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) return (false); { - SyncEventGuard guard (mEeRegisterEvent); + SyncEventGuard guard (mEeRegisterEvent); ALOGD ("%s: try ee register", fn); nfaStat = NFA_EeRegister (nfaEeCallback); if (nfaStat != NFA_STATUS_OK) @@ -187,7 +188,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) { ALOGD ("%s: Found HCI network, try hci register", fn); - SyncEventGuard guard (mHciRegisterEvent); + SyncEventGuard guard (mHciRegisterEvent); nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE); if (nfaStat != NFA_STATUS_OK) @@ -203,7 +204,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) mRouteDataSet.initialize (); mRouteDataSet.import (); //read XML file HostAidRouter::getInstance().initialize (); - + mIsInit = true; ALOGD ("%s: exit", fn); return (true); @@ -215,7 +216,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) ** Function: finalize ** ** Description: Release all resources. -** +** ** Returns: None ** *******************************************************************************/ @@ -250,7 +251,7 @@ void SecureElement::finalize () ** Function: getEeInfo ** ** Description: Get latest information about execution environments from stack. -** +** ** Returns: True if at least 1 EE is available. ** *******************************************************************************/ @@ -259,7 +260,7 @@ bool SecureElement::getEeInfo() static const char fn [] = "SecureElement::getEeInfo"; ALOGD ("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - UINT8 xx = 0, yy = 0; + UINT8 xx = 0, yy = 0; // If mbNewEE is true then there is new EE info. if (mbNewEE) @@ -274,7 +275,7 @@ bool SecureElement::getEeInfo() else { mbNewEE = false; - + ALOGD ("%s: num EEs discovered: %u", fn, mActualNumEe); if (mActualNumEe != 0) { @@ -308,7 +309,7 @@ bool SecureElement::getEeInfo() ** ** Description: Get the list of handles of all execution environments. ** e: Java Virtual Machine. -** +** ** Returns: List of handles of all execution environments. ** *******************************************************************************/ @@ -335,13 +336,13 @@ jintArray SecureElement::getListOfEeHandles (JNIEnv* e) int cnt = 0; for (int ii = 0; ii < mActualNumEe && cnt < mNumEePresent; ii++) { - ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle); + ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle); if ((mEeInfo[ii].num_interface == 0) || (mEeInfo[ii].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) { continue; } - jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE; + jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE; e->SetIntArrayRegion (list, cnt++, 1, &jj); } //e->DeleteLocalRef (list); @@ -357,7 +358,7 @@ jintArray SecureElement::getListOfEeHandles (JNIEnv* e) ** ** Description: Turn on the secure element. ** seID: ID of secure element. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -374,13 +375,13 @@ bool SecureElement::activate (jint seID) ALOGE ("%s: not init", fn); return false; } - + if (mActiveEeHandle != NFA_HANDLE_INVALID) { ALOGD ("%s: already active", fn); return true; } - + // Get Fresh EE info if needed. if (! getEeInfo()) { @@ -404,7 +405,7 @@ bool SecureElement::activate (jint seID) //activate every discovered secure element for (int index=0; index < mActualNumEe; index++) { - tNFA_EE_INFO& eeItem = mEeInfo[index]; + tNFA_EE_INFO& eeItem = mEeInfo[index]; if ((eeItem.ee_handle == EE_HANDLE_0xF3) || (eeItem.ee_handle == EE_HANDLE_0xF4)) { @@ -417,7 +418,7 @@ bool SecureElement::activate (jint seID) numActivatedEe++; continue; } - + { SyncEventGuard guard (mEeSetModeEvent); ALOGD ("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle); @@ -435,7 +436,7 @@ bool SecureElement::activate (jint seID) for (UINT8 xx = 0; xx < mActualNumEe; xx++) { - if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) && + if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) && (mEeInfo[xx].ee_status != NFC_NFCEE_STATUS_INACTIVE)) { mActiveEeHandle = mEeInfo[xx].ee_handle; @@ -454,7 +455,7 @@ bool SecureElement::activate (jint seID) ** ** Description: Turn off the secure element. ** seID: ID of secure element. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -576,7 +577,7 @@ TheEnd: ** Function: connectEE ** ** Description: Connect to the execution environment. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -590,7 +591,7 @@ bool SecureElement::connectEE () char pipeConfName[40]; tNFA_HANDLE eeHandle = mActiveEeHandle; - ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d", + ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d", fn, mActiveEeHandle, gSEId, gGatePipe, gUseStaticPipe); if (!mIsInit) @@ -636,7 +637,7 @@ bool SecureElement::connectEE () } else { - ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName); + ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName); } } else @@ -699,7 +700,7 @@ bool SecureElement::connectEE () if (mNewSourceGate == 0) { ALOGD ("%s: allocate gate", fn); - //allocate a source gate and store in mNewSourceGate + //allocate a source gate and store in mNewSourceGate SyncEventGuard guard (mAllocateGateEvent); if ((nfaStat = NFA_HciAllocGate (mNfaHciHandle)) != NFA_STATUS_OK) { @@ -723,7 +724,7 @@ bool SecureElement::connectEE () } mCreatePipeEvent.wait (); if (mCommandStatus != NFA_STATUS_OK) - goto TheEnd; + goto TheEnd; } { @@ -737,14 +738,14 @@ bool SecureElement::connectEE () } mPipeOpenedEvent.wait (); if (mCommandStatus != NFA_STATUS_OK) - goto TheEnd; + goto TheEnd; } } - + retVal = true; TheEnd: - mIsPiping = retVal; + mIsPiping = retVal; if (!retVal) { // if open failed we need to de-allocate the gate @@ -762,7 +763,7 @@ TheEnd: ** ** Description: Disconnect from the execution environment. ** seID: ID of secure element. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -792,13 +793,13 @@ bool SecureElement::disconnectEE (jint seID) ** Function: transceive ** ** Description: Send data to the secure element; read it's response. -** xmitBuffer: Data to transmit. +** xmitBuffer: Data to transmit. ** xmitBufferSize: Length of data. ** recvBuffer: Buffer to receive response. ** recvBufferMaxSize: Maximum size of buffer. ** recvBufferActualSize: Actual length of response. ** timeoutMillisec: timeout in millisecond. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -809,18 +810,18 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* tNFA_STATUS nfaStat = NFA_STATUS_FAILED; bool isSuccess = false; bool waitOk = false; - + ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); - { - SyncEventGuard guard (mTransceiveEvent); + { + SyncEventGuard guard (mTransceiveEvent); mActualResponseSize = 0; memset (mResponseData, 0, sizeof(mResponseData)); if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71)) nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); else nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); - + if (nfaStat == NFA_STATUS_OK) { waitOk = mTransceiveEvent.wait (timeoutMillisec); @@ -844,8 +845,8 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* memcpy (recvBuffer, mResponseData, recvBufferActualSize); isSuccess = true; - -TheEnd: + +TheEnd: ALOGD ("%s: exit; isSuccess: %d; recvBufferActualSize: %ld", fn, isSuccess, recvBufferActualSize); return (isSuccess); } @@ -857,7 +858,7 @@ TheEnd: ** ** Description: Notify the NFC service about RF field events from the stack. ** isActive: Whether any secure element is activated. -** +** ** Returns: None ** *******************************************************************************/ @@ -897,7 +898,7 @@ void SecureElement::notifyRfFieldEvent (bool isActive) ** ** Description: Store a copy of the execution environment information from the stack. ** info: execution environment information. -** +** ** Returns: None ** *******************************************************************************/ @@ -905,12 +906,12 @@ void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info) { static const char fn [] = "SecureElement::storeUiccInfo"; ALOGD ("%s: Status: %u Num EE: %u", fn, info.status, info.num_ee); - + SyncEventGuard guard (mUiccInfoEvent); memcpy (&mUiccInfo, &info, sizeof(mUiccInfo)); for (UINT8 xx = 0; xx < info.num_ee; xx++) { - //for each technology (A, B, F, B'), print the bit field that shows + //for each technology (A, B, F, B'), print the bit field that shows //what protocol(s) is support by that technology ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x", fn, xx, info.ee_disc_info[xx].ee_handle, @@ -930,7 +931,7 @@ void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info) ** Description: Get the ID of the secure element. ** eeHandle: Handle to the secure element. ** uid: Array to receive the ID. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -950,8 +951,8 @@ bool SecureElement::getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid) findUiccByHandle (eeHandle); //cannot get UID from the stack; nothing to do - -TheEnd: + +TheEnd: mNativeData->vm->DetachCurrentThread (); ALOGD ("%s: exit; ret=%u", fn, retval); return retval; @@ -965,7 +966,7 @@ TheEnd: ** Description: Get all the technologies supported by a secure element. ** eeHandle: Handle of secure element. ** techList: List to receive the technologies. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -976,7 +977,7 @@ bool SecureElement::getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList bool retval = false; JNIEnv* e = NULL; jint theList = 0; - + mNativeData->vm->AttachCurrentThread (&e, NULL); if (e == NULL) { @@ -996,8 +997,8 @@ bool SecureElement::getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList theList = TARGET_TYPE_ISO14443_3B; else theList = TARGET_TYPE_UNKNOWN; - -TheEnd: + +TheEnd: mNativeData->vm->DetachCurrentThread (); ALOGD ("%s: exit; ret=%u", fn, retval); return retval; @@ -1010,7 +1011,7 @@ TheEnd: ** ** Description: Adjust routes in the controller's listen-mode routing table. ** selection: which set of routes to configure the controller. -** +** ** Returns: None ** *******************************************************************************/ @@ -1035,7 +1036,7 @@ void SecureElement::adjustRoutes (RouteSelection selection) goto TheEnd; } - + TheEnd: NFA_EeUpdateNow (); //apply new routes now ALOGD ("%s: exit", fn); @@ -1047,7 +1048,7 @@ TheEnd: ** Function: applyRoutes ** ** Description: Read route data from file and apply them again. -** +** ** Returns: None ** *******************************************************************************/ @@ -1070,7 +1071,7 @@ void SecureElement::applyRoutes () ** ** Description: Adjust default routing based on protocol in NFC listen mode. ** isRouteToEe: Whether routing to EE (true) or host (false). -** +** ** Returns: None ** *******************************************************************************/ @@ -1080,7 +1081,7 @@ void SecureElement::adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelec ALOGD ("%s: enter", fn); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; const tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_ISO_DEP; - + /////////////////////// // delete route to host /////////////////////// @@ -1226,7 +1227,7 @@ void SecureElement::adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelec ** ** Description: Adjust default routing based on technology in NFC listen mode. ** isRouteToEe: Whether routing to EE (true) or host (false). -** +** ** Returns: None ** *******************************************************************************/ @@ -1236,7 +1237,7 @@ void SecureElement::adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSel ALOGD ("%s: enter", fn); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; const tNFA_TECHNOLOGY_MASK techMask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B; - + /////////////////////// // delete route to host /////////////////////// @@ -1383,7 +1384,7 @@ void SecureElement::adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSel ** Description: Receive execution environment-related events from stack. ** event: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -1412,7 +1413,7 @@ void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventD if (pEE) { pEE->ee_status ^= 1; - ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status); + ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status); } else ALOGE ("%s: NFA_EE_MODE_SET_EVT; EE: 0x%04x not found. mActiveEeHandle: 0x%04x", fn, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle); @@ -1421,7 +1422,7 @@ void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventD sSecElem.mEeSetModeEvent.notifyOne(); } break; - + case NFA_EE_SET_TECH_CFG_EVT: { ALOGD ("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, eventData->status); @@ -1437,7 +1438,7 @@ void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventD sSecElem.mRoutingEvent.notifyOne (); } break; - + case NFA_EE_ACTION_EVT: { tNFA_EE_ACTION& action = eventData->action; @@ -1474,11 +1475,11 @@ void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventD eventData->discover_req.status, eventData->discover_req.num_ee); sSecElem.storeUiccInfo (eventData->discover_req); break; - + case NFA_EE_NO_CB_ERR_EVT: ALOGD ("%s: NFA_EE_NO_CB_ERR_EVT status=%u", fn, eventData->status); break; - + case NFA_EE_ADD_AID_EVT: { ALOGD ("%s: NFA_EE_ADD_AID_EVT status=%u", fn, eventData->status); @@ -1494,10 +1495,10 @@ void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventD sSecElem.mAidAddRemoveEvent.notifyOne (); } break; - + case NFA_EE_NEW_EE_EVT: { - ALOGD ("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn, + ALOGD ("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn, eventData->new_ee.ee_handle, eventData->new_ee.ee_status); // Indicate there are new EE sSecElem.mbNewEE = true; @@ -1515,7 +1516,7 @@ void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventD ** Function getSeVerInfo ** ** Description Gets version information and id for a secure element. The -** seIndex parmeter is the zero based index of the secure +** seIndex parmeter is the zero based index of the secure ** element to get verion info for. The version infommation ** is returned as a string int the verInfo parameter. ** @@ -1537,7 +1538,7 @@ bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UIN if ((mEeInfo[seIndex].num_interface == 0) || (mEeInfo[seIndex].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) ) { return false; - } + } strncpy(verInfo, "Version info not available", verInfoSz-1); verInfo[verInfoSz-1] = '\0'; @@ -1556,7 +1557,7 @@ bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UIN { if (false == mVerInfoEvent.wait(200)) { - ALOGE ("%s: wait response timeout", __FUNCTION__); + ALOGE ("%s: wait response timeout", __FUNCTION__); } else { @@ -1592,7 +1593,7 @@ UINT8 SecureElement::getActualNumEe() ** Description: Receive Host Controller Interface-related events from stack. ** event: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -1631,7 +1632,7 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event sSecElem.mDeallocateGateEvent.notifyOne(); } break; - + case NFA_HCI_GET_GATE_PIPE_LIST_EVT: { ALOGD ("%s: NFA_HCI_GET_GATE_PIPE_LIST_EVT; status=0x%X; num_pipes: %u num_gates: %u", fn, @@ -1666,7 +1667,7 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event case NFA_HCI_EVENT_SENT_EVT: ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status); break; - + case NFA_HCI_RSP_RCVD_EVT: //response received from secure element { tNFA_HCI_RSP_RCVD& rsp_rcvd = eventData->rsp_rcvd; @@ -1728,7 +1729,7 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event ** ** Description: Find information about an execution environment. ** eeHandle: Handle to execution environment. -** +** ** Returns: Information about an execution environment. ** *******************************************************************************/ @@ -1748,7 +1749,7 @@ tNFA_EE_INFO *SecureElement::findEeByHandle (tNFA_HANDLE eeHandle) ** Function: getDefaultEeHandle ** ** Description: Get the handle to the execution environment. -** +** ** Returns: Handle to the execution environment. ** *******************************************************************************/ @@ -1760,7 +1761,7 @@ tNFA_HANDLE SecureElement::getDefaultEeHandle () if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) ) return (mEeInfo[xx].ee_handle); } - return NFA_HANDLE_INVALID; + return NFA_HANDLE_INVALID; } @@ -1770,7 +1771,7 @@ tNFA_HANDLE SecureElement::getDefaultEeHandle () ** ** Description: Find information about an execution environment. ** eeHandle: Handle of the execution environment. - ** + ** ** Returns: Information about the execution environment. ** *******************************************************************************/ @@ -1794,7 +1795,7 @@ tNFA_EE_DISCOVER_INFO *SecureElement::findUiccByHandle (tNFA_HANDLE eeHandle) ** ** Description: Convert status code to status text. ** status: Status code -** +** ** Returns: None ** *******************************************************************************/ @@ -1820,7 +1821,7 @@ const char* SecureElement::eeStatusToString (UINT8 status) ** Description: Receive card-emulation related events from stack. ** event: Event code. ** eventData: Event data. -** +** ** Returns: None ** *******************************************************************************/ @@ -1844,7 +1845,7 @@ void SecureElement::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eve ** ** Description: Adjust controller's listen-mode routing table so transactions ** are routed to the secure elements. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1873,9 +1874,9 @@ bool SecureElement::routeToSecureElement () ALOGE ("%s: invalid EE handle", fn); return false; } - + adjustRoutes (SecElemRoute); - + { unsigned long num = 0; if (GetNumValue("UICC_LISTEN_TECH_MASK", &num, sizeof(num))) @@ -1891,7 +1892,7 @@ bool SecureElement::routeToSecureElement () else ALOGE ("%s: fail to start UICC listen", fn); } - + ALOGD ("%s: exit; ok=%u", fn, retval); return retval; } @@ -1903,7 +1904,7 @@ bool SecureElement::routeToSecureElement () ** ** Description: Adjust controller's listen-mode routing table so transactions ** are routed to the default destination. -** +** ** Returns: True if ok. ** *******************************************************************************/ @@ -1939,7 +1940,7 @@ bool SecureElement::routeToDefault () } adjustRoutes (DefaultRoute); - + ALOGD ("%s: exit; ok=%u", fn, retval); return retval; } @@ -1951,7 +1952,7 @@ bool SecureElement::routeToDefault () ** ** Description: Whether controller is routing listen-mode events to ** secure elements or a pipe is connected. -** +** ** Returns: True if either case is true. ** *******************************************************************************/ diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index 8bfb8f5..ea1f568 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -2,7 +2,7 @@ ** ** Name: SecureElement.h ** -** Description: Communicate with secure elements that are attached +** Description: Communicate with secure elements that are attached ** to the NFC controller. ** ** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. @@ -28,19 +28,19 @@ class SecureElement { public: tNFA_HANDLE mActiveEeHandle; - + /******************************************************************************* ** ** Function: getInstance ** ** Description: Get the SecureElement singleton object. - ** + ** ** Returns: SecureElement object. ** *******************************************************************************/ static SecureElement& getInstance (); - + /******************************************************************************* ** @@ -48,24 +48,24 @@ public: ** ** Description: Initialize all member variables. ** native: Native data. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool initialize (nfc_jni_native_data* native); - - + + /******************************************************************************* ** ** Function: finalize ** ** Description: Release all resources. - ** + ** ** Returns: None ** *******************************************************************************/ void finalize (); - + /******************************************************************************* ** @@ -73,12 +73,12 @@ public: ** ** Description: Get the list of handles of all execution environments. ** e: Java Virtual Machine. - ** + ** ** Returns: List of handles of all execution environments. ** *******************************************************************************/ jintArray getListOfEeHandles (JNIEnv* e); - + /******************************************************************************* ** @@ -86,20 +86,20 @@ public: ** ** Description: Turn on the secure element. ** seID: ID of secure element. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool activate (jint seID); - + /******************************************************************************* ** ** Function: deactivate ** ** Description: Turn off the secure element. ** seID: ID of secure element. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -111,7 +111,7 @@ public: ** Function: connectEE ** ** Description: Connect to the execution environment. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -124,7 +124,7 @@ public: ** ** Description: Disconnect from the execution environment. ** seID: ID of secure element. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -136,13 +136,13 @@ public: ** Function: transceive ** ** Description: Send data to the secure element; read it's response. - ** xmitBuffer: Data to transmit. + ** xmitBuffer: Data to transmit. ** xmitBufferSize: Length of data. ** recvBuffer: Buffer to receive response. ** recvBufferMaxSize: Maximum size of buffer. ** recvBufferActualSize: Actual length of response. ** timeoutMillisec: timeout in millisecond - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -156,7 +156,7 @@ public: ** ** Description: Notify the NFC service about RF field events from the stack. ** isActive: Whether any secure element is activated. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -169,7 +169,7 @@ public: ** ** Description: Store a copy of the execution environment information from the stack. ** info: execution environment information. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -183,7 +183,7 @@ public: ** Description: Get the ID of the secure element. ** eeHandle: Handle to the secure element. ** uid: Array to receive the ID. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -197,7 +197,7 @@ public: ** Description: Get all the technologies supported by a secure element. ** eeHandle: Handle of secure element. ** techList: List to receive the technologies. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ @@ -211,7 +211,7 @@ public: ** Description: Notify the NFC service about a transaction event from secure element. ** aid: Buffer contains application ID. ** aidLen: Length of application ID. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -240,7 +240,7 @@ public: ** Description: Receive card-emulation related events from stack. ** event: Event code. ** eventData: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -253,7 +253,7 @@ public: ** ** Description: Read route data from XML and apply them again ** to every secure element. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -272,39 +272,39 @@ public: *******************************************************************************/ void setActiveSeOverride (UINT8 activeSeOverride); - + /******************************************************************************* ** ** Function: routeToSecureElement ** ** Description: Adjust controller's listen-mode routing table so transactions ** are routed to the secure elements as specified in route.xml. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool routeToSecureElement (); - - + + /******************************************************************************* ** ** Function: routeToDefault ** ** Description: Adjust controller's listen-mode routing table so transactions ** are routed to the default destination specified in route.xml. - ** + ** ** Returns: True if ok. ** *******************************************************************************/ bool routeToDefault (); - - + + /******************************************************************************* ** ** Function: isBusy ** ** Description: Whether NFC controller is routing listen-mode events or a pipe is connected. - ** + ** ** Returns: True if either case is true. ** *******************************************************************************/ @@ -328,7 +328,7 @@ public: ** Function getSeVerInfo ** ** Description Gets version information and id for a secure element. The - ** seIndex parmeter is the zero based index of the secure + ** seIndex parmeter is the zero based index of the secure ** element to get verion info for. The version infommation ** is returned as a string int the verInfo parameter. ** @@ -345,10 +345,10 @@ private: static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe static const UINT8 STATIC_PIPE_0x71 = 0x71; //Broadcom's proprietary static pipe static const UINT8 EVT_SEND_DATA = 0x10; //see specification ETSI TS 102 622 v9.0.0 (Host Controller Interface); section 9.3.3.3 - static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0 - static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1 + static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0 + static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1 static SecureElement sSecElem; - + UINT8 mDestinationGate; //destination gate of the UICC tNFA_HANDLE mNfaHciHandle; //NFA handle to NFA's HCI component nfc_jni_native_data* mNativeData; @@ -409,7 +409,7 @@ private: *******************************************************************************/ ~SecureElement (); - + /******************************************************************************* ** ** Function: nfaEeCallback @@ -417,7 +417,7 @@ private: ** Description: Receive execution environment-related events from stack. ** event: Event code. ** eventData: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -431,7 +431,7 @@ private: ** Description: Receive Host Controller Interface-related events from stack. ** event: Event code. ** eventData: Event data. - ** + ** ** Returns: None ** *******************************************************************************/ @@ -444,7 +444,7 @@ private: ** ** Description: Find information about an execution environment. ** eeHandle: Handle to execution environment. - ** + ** ** Returns: Information about an execution environment. ** *******************************************************************************/ @@ -457,7 +457,7 @@ private: ** ** Description: Find information about an execution environment. ** eeHandle: Handle of the execution environment. - ** + ** ** Returns: Information about the execution environment. ** *******************************************************************************/ @@ -469,33 +469,33 @@ private: ** Function: getDefaultEeHandle ** ** Description: Get the handle to the execution environment. - ** + ** ** Returns: Handle to the execution environment. ** *******************************************************************************/ tNFA_HANDLE getDefaultEeHandle (); - + /******************************************************************************* ** ** Function: adjustRoutes ** ** Description: Adjust routes in the controller's listen-mode routing table. ** selection: which set of routes to configure the controller. - ** + ** ** Returns: None ** *******************************************************************************/ void adjustRoutes (RouteSelection selection); - + /******************************************************************************* ** ** Function: adjustProtocolRoutes ** ** Description: Adjust default routing based on protocol in NFC listen mode. ** isRouteToEe: Whether routing to EE (true) or host (false). - ** + ** ** Returns: None ** *******************************************************************************/ @@ -508,7 +508,7 @@ private: ** ** Description: Adjust default routing based on technology in NFC listen mode. ** isRouteToEe: Whether routing to EE (true) or host (false). - ** + ** ** Returns: None ** *******************************************************************************/ @@ -520,12 +520,12 @@ private: ** Function: getEeInfo ** ** Description: Get latest information about execution environments from stack. - ** + ** ** Returns: True if at least 1 EE is available. ** *******************************************************************************/ bool getEeInfo (); - + /******************************************************************************* ** @@ -533,7 +533,7 @@ private: ** ** Description: Convert status code to status text. ** status: Status code - ** + ** ** Returns: None ** *******************************************************************************/ diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h index 5828569..5ab5d43 100644 --- a/nci/jni/SyncEvent.h +++ b/nci/jni/SyncEvent.h @@ -19,25 +19,25 @@ class SyncEvent public: /******************************************************************************* ** - ** Function: ~SyncEvent + ** Function: ~SyncEvent ** ** Description: Cleanup all resources. - ** + ** ** Returns: None. ** *******************************************************************************/ - ~SyncEvent () + ~SyncEvent () { - mMutex.unlock (); + mMutex.unlock (); } - + /******************************************************************************* ** ** Function: start ** - ** Description: Start a synchronization operation. - ** + ** Description: Start a synchronization operation. + ** ** Returns: None. ** *******************************************************************************/ @@ -46,71 +46,71 @@ public: mMutex.lock (); } - + /******************************************************************************* ** ** Function: wait ** ** Description: Block the thread and wait for the event to occur. - ** + ** ** Returns: None. ** *******************************************************************************/ void wait () - { + { mCondVar.wait (mMutex); end (); } - + /******************************************************************************* ** ** Function: wait ** ** Description: Block the thread and wait for the event to occur. ** millisec: Timeout in milliseconds. - ** + ** ** Returns: True if wait is successful; false if timeout occurs. ** *******************************************************************************/ bool wait (long millisec) - { + { bool retVal = mCondVar.wait (mMutex, millisec); end (); return retVal; } - + /******************************************************************************* ** - ** Function: notifyOne + ** Function: notifyOne + ** + ** Description: Notify a blocked thread that the event has occured. Unblocks it. ** - ** Description: Notify a blocked thread that the event has occured. Unblocks it. - ** ** Returns: None. ** *******************************************************************************/ - void notifyOne () - { - mCondVar.notifyOne (); + void notifyOne () + { + mCondVar.notifyOne (); end (); } - + /******************************************************************************* ** - ** Function: end + ** Function: end + ** + ** Description: End a synchronization operation. ** - ** Description: End a synchronization operation. - ** ** Returns: None. ** *******************************************************************************/ - void end () - { + void end () + { mMutex.unlock (); } - + private: CondVar mCondVar; Mutex mMutex; @@ -133,10 +133,10 @@ class SyncEventGuard public: /******************************************************************************* ** - ** Function: SyncEventGuard + ** Function: SyncEventGuard ** ** Description: Start a synchronization operation. - ** + ** ** Returns: None. ** *******************************************************************************/ @@ -145,14 +145,14 @@ public: { event.start (); //automatically start operation }; - + /******************************************************************************* ** - ** Function: ~SyncEventGuard + ** Function: ~SyncEventGuard ** ** Description: End a synchronization operation. - ** + ** ** Returns: None. ** *******************************************************************************/ @@ -160,7 +160,7 @@ public: { mEvent.end (); //automatically end operation }; - + private: SyncEvent& mEvent; }; -- cgit v1.1 From 7de0211f2c47500f921634d9af18900826000616 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Tue, 14 Aug 2012 17:48:35 -0400 Subject: Reduce compilation warnings in NFC JNI. Change-Id: Iba0dab66be054ca1b0bc0f477c1107909df65cda --- nci/jni/NativeNfcManager.cpp | 3 ++- nci/jni/PeerToPeer.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 0850f8a..330e38d 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -671,8 +671,9 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) { unsigned long num = 0; - tBRCM_DEV_INIT_CONFIG devInitConfig = {0}; + tBRCM_DEV_INIT_CONFIG devInitConfig; + memset (&devInitConfig, 0, sizeof(devInitConfig)); NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Initialize(); //start GKI, NCI task, NFC task diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 1272bf9..0622ac0 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -745,7 +745,7 @@ bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* se // Save JNI Handle and try to connect to SNEP mJniHandleSendingNppViaSnep = jniHandle; - if (NFA_SnepConnect (mSnepRegHandle, "urn:nfc:sn:snep") == NFA_STATUS_OK) + if (NFA_SnepConnect (mSnepRegHandle, const_cast("urn:nfc:sn:snep")) == NFA_STATUS_OK) { SyncEventGuard guard (pClient->mSnepEvent); pClient->mSnepEvent.wait(); -- cgit v1.1 From 5e100450dac446c851690af1a522446fa406e4ad Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 16 Aug 2012 13:47:49 -0700 Subject: Don't call applyRouting on disable(). Original patch from Chih-Weih Huang . Change-Id: I15b129d318d125cf67aba83d16441c6d52bb193a --- src/com/android/nfc/NfcService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 5f9fc21..3acfa1c 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -597,7 +597,6 @@ public class NfcService extends Application implements DeviceHostListener { // A convenient way to stop the watchdog properly consists of // disconnecting the tag. The polling loop shall be stopped before // to avoid the tag being discovered again. - applyRouting(true); maybeDisconnectTarget(); mNfcDispatcher.setForegroundDispatch(null, null, null); -- cgit v1.1 From 55dbe428a7134ec82c5356f4f8e5fd7778374509 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Mon, 13 Aug 2012 15:34:30 -0400 Subject: Remove gJniVersion; add thread-synchronization Remove gJniVersion. Add thread-synchronization for obtaining a new JNI handle. Change-Id: I23e05c95fd90005f6ef1cac69e1e07f0b9612227 --- nci/jni/NativeLlcpServiceSocket.cpp | 3 +-- nci/jni/NativeNfcManager.cpp | 32 ++++++++---------------- nci/jni/NativeNfcTag.cpp | 5 +--- nci/jni/NfcTag.cpp | 3 +-- nci/jni/PeerToPeer.cpp | 50 ++++++++++++++++--------------------- nci/jni/PeerToPeer.h | 19 +++++++++++--- 6 files changed, 51 insertions(+), 61 deletions(-) diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp index ca57410..7572690 100644 --- a/nci/jni/NativeLlcpServiceSocket.cpp +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -24,7 +24,6 @@ extern "C" #include "nfa_api.h" #include "nfa_p2p_api.h" } -extern tBRCM_JNI_HANDLE gNextJniHandle; namespace android @@ -56,7 +55,7 @@ static jobject nativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jfieldID f = 0; tBRCM_JNI_HANDLE serverHandle; //handle of the local server bool stat = false; - tBRCM_JNI_HANDLE connHandle = gNextJniHandle++; + tBRCM_JNI_HANDLE connHandle = PeerToPeer::getInstance().getNewJniHandle (); ALOGD ("%s: enter", __FUNCTION__); diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 330e38d..2767f76 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -68,8 +68,6 @@ namespace android ** public variables and functions ** *****************************************************************************/ -tBRCM_JNI_HANDLE gNextJniHandle = 1; -long gJniVersion = 411; namespace android { @@ -470,13 +468,13 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) /* Initialize native cached references */ gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID (cls, - "notifyNdefMessageListeners",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V" : "(Lcom/android/nfc/NativeNfcTag;)V"); + "notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V"); gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID (cls, "notifyTransactionListeners", "([B)V"); gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID (cls, - "notifyLlcpLinkActivation",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V" : "(Lcom/android/nfc/NativeP2pDevice;)V"); + "notifyLlcpLinkActivation", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID (cls, - "notifyLlcpLinkDeactivated",(gJniVersion >= 401) ? "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V" : "(Lcom/android/nfc/NativeP2pDevice;)V"); + "notifyLlcpLinkDeactivated", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V"); sCachedNfcManagerNotifyTargetDeselected = e->GetMethodID (cls, "notifyTargetDeselected","()V"); gCachedNfcManagerNotifySeFieldActivated = e->GetMethodID (cls, @@ -484,23 +482,14 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID (cls, "notifySeFieldDeactivated", "()V"); - if (gJniVersion > 235) - { - sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls, + sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls, "notifySeApduReceived", "([B)V"); - sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls, + sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls, "notifySeMifareAccess", "([B)V"); - sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls, + sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls, "notifySeEmvCardRemoval", "()V"); - } - else - { - sCachedNfcManagerNotifySeApduReceived = NULL; - sCachedNfcManagerNotifySeMifareAccess = NULL; - sCachedNfcManagerNotifySeEmvCardRemoval = NULL; - } if (nfc_jni_cache_object(e,gNativeNfcTagClassName, &(nat->cached_NfcTag)) == -1) { @@ -711,7 +700,7 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) SecureElement::getInstance().initialize (getNative(e, o)); nativeNfcTag_registerNdefTypeHandler (); NfcTag::getInstance().initialize (getNative(e, o)); - PeerToPeer::getInstance().initialize (gJniVersion); + PeerToPeer::getInstance().initialize (); PeerToPeer::getInstance().handleNfcOnOff (true); ///////////////////////////////////////////////////////////////////////////////// @@ -939,7 +928,7 @@ static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject o, jint jobject serviceSocket = NULL; jclass clsNativeLlcpServiceSocket = NULL; jfieldID f = 0; - tBRCM_JNI_HANDLE jniHandle = gNextJniHandle++; + tBRCM_JNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle (); const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* std::string serviceName2 (serviceName); @@ -1090,7 +1079,7 @@ static jobject nfcManager_doCreateLlcpSocket (JNIEnv* e, jobject o, jint nSap, j jobject clientSocket = NULL; jclass clsNativeLlcpSocket; jfieldID f; - tBRCM_JNI_HANDLE jniHandle = gNextJniHandle++; + tBRCM_JNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle (); bool stat = false; stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw); @@ -1582,8 +1571,7 @@ static JNINativeMethod gMethods[] = *******************************************************************************/ int register_com_android_nfc_NativeNfcManager (JNIEnv *e) { - GetNumValue (NAME_JNI_VERSION, &gJniVersion, sizeof(gJniVersion)); - ALOGD ("%s: enter, %s=%lu", __FUNCTION__, NAME_JNI_VERSION, gJniVersion); + ALOGD ("%s: enter", __FUNCTION__); PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL); ALOGD ("%s: exit", __FUNCTION__); return jniRegisterNativeMethods (e, gNativeNfcManagerClassName, gMethods, NELEM (gMethods)); diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index 53c2384..f270bec 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -40,7 +40,6 @@ namespace android extern bool nfcManager_isNfcActive(); extern int gGeneralTransceiveTimeout; } -extern long gJniVersion; /***************************************************************************** @@ -1545,9 +1544,7 @@ static JNINativeMethod gMethods[] = *******************************************************************************/ int register_com_android_nfc_NativeNfcTag (JNIEnv *e) { - GetNumValue (NAME_JNI_VERSION, &gJniVersion, sizeof(gJniVersion)); - ALOGD ("%s: enter, %s=%ld", __FUNCTION__, NAME_JNI_VERSION, gJniVersion); - ALOGD ("%s: exit; using %s", __FUNCTION__, gNativeNfcTagClassName); + ALOGD ("%s", __FUNCTION__); return jniRegisterNativeMethods (e, gNativeNfcTagClassName, gMethods, NELEM (gMethods)); } diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp index ebec941..9d629a2 100755 --- a/nci/jni/NfcTag.cpp +++ b/nci/jni/NfcTag.cpp @@ -15,7 +15,6 @@ extern "C" #include "rw_int.h" } -extern long gJniVersion; namespace android { @@ -580,7 +579,7 @@ void NfcTag::fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, t ALOGD ("%s", fn); jfieldID f = NULL; - f = e->GetFieldID (tag_cls, (gJniVersion >= 401) ? "mConnectedTechIndex" : "mConnectedTechnology", "I"); + f = e->GetFieldID (tag_cls, "mConnectedTechIndex", "I"); e->SetIntField (tag, f, (jint) 0); } diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 0622ac0..3c46a02 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -51,7 +51,7 @@ PeerToPeer::PeerToPeer () mNppTotalLen (0), mNppReadSoFar (0), mNdefTypeHandlerHandle (NFA_HANDLE_INVALID), - mJniVersion (403) + mNextJniHandle (1) { unsigned long num = 0; memset (mServers, 0, sizeof(mServers)); @@ -93,16 +93,13 @@ PeerToPeer& PeerToPeer::getInstance () ** Function: initialize ** ** Description: Initialize member variables. -** jniVersion: JNI version. ** ** Returns: None ** *******************************************************************************/ -void PeerToPeer::initialize (long jniVersion) +void PeerToPeer::initialize () { ALOGD ("PeerToPeer::initialize"); - mJniVersion = jniVersion; - unsigned long num = 0; if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) @@ -1422,29 +1419,6 @@ void PeerToPeer::handleNfcOnOff (bool isOn) // Start with no clients or servers memset (mServers, 0, sizeof(mServers)); memset (mClients, 0, sizeof(mClients)); - - //Android older than 4.0.3 (Ice Cream Sandwich) do not have SNEP in the - //NFC service, so the JNI and stack have to implement SNEP. - if (mJniVersion < 403) - { - { - SyncEventGuard guard (mSnepDefaultServerStartStopEvent); - stat = NFA_SnepStartDefaultServer (snepClientCallback); - if (stat == NFA_STATUS_OK) - mSnepDefaultServerStartStopEvent.wait (); //wait for NFA_SNEP_DEFAULT_SERVER_STARTED_EVT - else - ALOGE ("%s: fail start snep server; error=0x%X", fn, stat); - } - - { - SyncEventGuard guard (mSnepRegisterEvent); - stat = NFA_SnepRegisterClient (snepClientCallback); - if (stat == NFA_STATUS_OK) - mSnepRegisterEvent.wait (); //wait for NFA_SNEP_REG_EVT - else - ALOGE ("%s: fail register snep client; error=0x%X", fn, stat); - } - } } else { @@ -2020,6 +1994,26 @@ void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventD } +/******************************************************************************* +** +** Function: getNextJniHandle +** +** Description: Get a new JNI handle. +** +** Returns: A new JNI handle. +** +*******************************************************************************/ +tBRCM_JNI_HANDLE PeerToPeer::getNewJniHandle () +{ + tBRCM_JNI_HANDLE newHandle = 0; + + mNewJniHandleMutex.lock (); + newHandle = mNextJniHandle++; + mNewJniHandleMutex.unlock (); + return newHandle; +} + + ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index b9c7b39..d689298 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -78,12 +78,11 @@ public: ** Function: initialize ** ** Description: Initialize member variables. - ** jniVersion: JNI version. ** ** Returns: None ** *******************************************************************************/ - void initialize (long jniVersion); + void initialize (); /******************************************************************************* @@ -320,6 +319,19 @@ public: *******************************************************************************/ void handleNfcOnOff (bool isOn); + + /******************************************************************************* + ** + ** Function: getNextJniHandle + ** + ** Description: Get a new JNI handle. + ** + ** Returns: A new JNI handle. + ** + *******************************************************************************/ + tBRCM_JNI_HANDLE getNewJniHandle (); + + private: static const int sMax = 10; static PeerToPeer sP2p; @@ -335,7 +347,7 @@ private: UINT32 mNppTotalLen; UINT32 mNppReadSoFar; tNFA_HANDLE mNdefTypeHandlerHandle; - long mJniVersion; + tBRCM_JNI_HANDLE mNextJniHandle; P2pServer *mServers [sMax]; P2pClient *mClients [sMax]; @@ -343,6 +355,7 @@ private: SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer() SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient() Mutex mDisconnectMutex; // synchronize the disconnect operation + Mutex mNewJniHandleMutex; // synchronize the creation of a new JNI handle /******************************************************************************* -- cgit v1.1 From 72a693f626c4c766f8f8d835c28643252301fef5 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Thu, 16 Aug 2012 17:26:52 -0400 Subject: Remove unused functions; correct spelling Remove unused functions; correct spelling Change-Id: I6ecf17f8cf8eeae831ba3fcc0a2eb492332c0cb6 --- nci/jni/NativeNfcTag.cpp | 81 ++---------------------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index f270bec..25b9826 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -631,24 +631,6 @@ static bool switchRfInterface (tNFA_INTF_TYPE rfInterface) return rVal; } -/******************************************************************************* -** -** Function: nativeNfcTag_doConnect_z -** -** Description: Connect to the tag in RF field. -** e: JVM environment. -** o: Java object. -** targetHandle: Handle of the tag. -** -** Returns: True if ok. -** -*******************************************************************************/ -static jboolean nativeNfcTag_doConnect_z (JNIEnv *e, jobject o, jint targetHandle) -{ - jint result = nativeNfcTag_doConnect (e, o, targetHandle); - return result == NFCSTATUS_SUCCESS ? JNI_TRUE : JNI_FALSE; -} - /******************************************************************************* ** @@ -681,24 +663,6 @@ static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o) return reSelect(intf); } -/******************************************************************************* -** -** Function: nativeNfcTag_doReconnect_z -** -** Description: Re-connect to the tag in RF field. -** e: JVM environment. -** o: Java object. -** -** Returns: True if ok. -** -*******************************************************************************/ -static jboolean nativeNfcTag_doReconnect_z (JNIEnv *e, jobject o) -{ - ALOGD ("%s", __FUNCTION__); - //do nothing as the tag has already been activated - return JNI_TRUE; -} - /******************************************************************************* ** @@ -721,25 +685,6 @@ static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHan /******************************************************************************* ** -** Function: nativeNfcTag_doHandleReconnect_z -** -** Description: Re-connect to the tag in RF field. -** e: JVM environment. -** o: Java object. -** targetHandle: Handle of the tag. -** -** Returns: True if ok. -** -*******************************************************************************/ -static jboolean nativeNfcTag_doHandleReconnect_z (JNIEnv *e, jobject o, jint targetHandle) -{ - ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle); - return nativeNfcTag_doConnect_z (e, o, targetHandle); -} - - -/******************************************************************************* -** ** Function: nativeNfcTag_doDisconnect ** ** Description: Deactivate the RF field. @@ -851,7 +796,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da { if (natTag.mTechList[1] == TARGET_TYPE_MIFARE_CLASSIC) { - // MifareClassic tag, we do not support transeive for this + // MifareClassic tag, we do not support transceive for this if (statusTargetLost) { targetLost = e->GetIntArrayElements (statusTargetLost, 0); @@ -902,7 +847,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da waitOk = sTransceiveEvent.wait (gGeneralTransceiveTimeout); } - if (waitOk == false) //if timeout occured + if (waitOk == false) //if timeout occurred { ALOGE ("%s: wait response timeout", __FUNCTION__); if (targetLost) @@ -1179,28 +1124,6 @@ TheEnd: /******************************************************************************* ** -** Function: nativeNfcTag_doCheckNdef_z -** -** Description: Does the tag contain a NDEF message? -** e: JVM environment. -** o: Java object. -** ndefInfo: NDEF info. -** -** Returns: True if tag contains a NDEF message. -** -*******************************************************************************/ -static bool nativeNfcTag_doCheckNdef_z (JNIEnv *e, jobject o, jintArray ndefInfo) -{ - ALOGD ("%s: enter", __FUNCTION__); - jint result = nativeNfcTag_doCheckNdef (e, o, ndefInfo); - bool retval = (result == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE; - ALOGD ("%s: exit; detected NDEF=%u", __FUNCTION__, retval); - return retval; -} - - -/******************************************************************************* -** ** Function: nativeNfcTag_resetPresenceCheck ** ** Description: Reset variables related to presence-check. -- cgit v1.1 From e8e49093826aa8309f4e16e5cd02174829e0310a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 16 Aug 2012 17:35:26 -0700 Subject: Log NFC controller firmware version. ALOGD is now squelched by default. Moved it to ALOGE. Change-Id: I3bb7601e65d01d8d01a95902a0be95c7e1a3426f --- nci/jni/NativeNfcManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 2767f76..40b9539 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -622,7 +622,7 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) tNFA_BRCM_FW_BUILD_INFO* bldInfo = (tNFA_BRCM_FW_BUILD_INFO*) eventData->p_vs_evt_data; if (bldInfo != NULL) { - ALOGD("BCM2079x NFC FW version %d.%d", bldInfo->patch.major_ver, + ALOGE("BCM2079x NFC FW version %d.%d", bldInfo->patch.major_ver, bldInfo->patch.minor_ver); } sNfaBuildInfoEvent.notifyOne(); -- cgit v1.1 From 22b1a3096cdb66ba2fbc540e1a8cacce701c6d82 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Sun, 19 Aug 2012 20:05:02 -0700 Subject: Use new display manager API. Change-Id: I4d40a33bf11379845464f4072471c168f9dccf75 --- src/com/android/nfc/SendUi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/nfc/SendUi.java b/src/com/android/nfc/SendUi.java index 23602c9..c54f54e 100644 --- a/src/com/android/nfc/SendUi.java +++ b/src/com/android/nfc/SendUi.java @@ -183,7 +183,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener, // We're only allowed to use hardware acceleration if // isHighEndGfx() returns true - otherwise, we're too limited // on resources to do it. - mHardwareAccelerated = ActivityManager.isHighEndGfx(mDisplay); + mHardwareAccelerated = ActivityManager.isHighEndGfx(); int hwAccelerationFlags = mHardwareAccelerated ? WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0; -- cgit v1.1 From 59ff0d6e6f4de4703a4489144a4311405eeead5a Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Thu, 23 Aug 2012 17:46:51 -0400 Subject: During nfcManager_disableDiscovery() go to power-off-sleep mode. BLTH01634648: During nfcManager_disableDiscovery() go to power-off-sleep mode when secure element is not selected. Change-Id: I85c37fa635a90fdc8c90b5a86fe1d3e091d421d4 --- nci/jni/NativeNfcManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 40b9539..9adeed3 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -838,6 +838,8 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) if (sDiscoveryEnabled == false) { ALOGD ("%s: already disabled", __FUNCTION__); + if (! sIsSecElemSelected) + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); goto TheEnd; } -- cgit v1.1 From d1235cf7c2d0839264ccf90e9be7e19b66b58b6a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 28 Aug 2012 10:39:39 +0200 Subject: Don't report empty NDEF tags as formattable. This was regression from a JB change. Change-Id: Idbd92abf797478ec827dc26d6e825e2a6805356d --- nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java | 1 + 1 file changed, 1 insertion(+) diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java index 45a59d2..992e6d2 100755 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java @@ -789,6 +789,7 @@ public class NativeNfcTag implements TagEndpoint { getConnectedLibNfcType(), getConnectedTechnology(), supportedNdefLength, cardState); + foundFormattable = false; reconnect(); } break; -- cgit v1.1 From dfc52b4bafc435e72d25aaba736612352bfd0581 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Fri, 17 Aug 2012 10:41:21 -0400 Subject: In SyncEvent class, only unlock mutex once In SyncEvent class, only unlock mutex once. Change-Id: I0fb797c9e6e8ea793fd38abd72a0c2780a734e95 --- nci/jni/Mutex.cpp | 4 +- nci/jni/NativeNfcManager.cpp | 44 ++++++++++++---------- nci/jni/NativeNfcTag.cpp | 64 +++++++++++++++++--------------- nci/jni/PeerToPeer.cpp | 88 ++++++++++++++++++++++++-------------------- nci/jni/SecureElement.cpp | 2 +- nci/jni/SyncEvent.h | 4 -- 6 files changed, 110 insertions(+), 96 deletions(-) diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp index a6b1397..6ccb87b 100644 --- a/nci/jni/Mutex.cpp +++ b/nci/jni/Mutex.cpp @@ -85,7 +85,7 @@ void Mutex::unlock () int res = pthread_mutex_unlock (&mMutex); if (res != 0) { - ALOGE ("Mutex::lock: fail unlock; error=0x%X", res); + ALOGE ("Mutex::unlock: fail unlock; error=0x%X", res); } } @@ -104,7 +104,7 @@ bool Mutex::tryLock () int res = pthread_mutex_trylock (&mMutex); if ((res != 0) && (res != EBUSY)) { - ALOGE ("Mutex::lock: fail try-lock; error=0x%X", res); + ALOGE ("Mutex::tryLock: error=0x%X", res); } return res == 0; } diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 9adeed3..69a9c3f 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -625,6 +625,7 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) ALOGE("BCM2079x NFC FW version %d.%d", bldInfo->patch.major_ver, bldInfo->patch.minor_ver); } + SyncEventGuard versionGuard (sNfaBuildInfoEvent); sNfaBuildInfoEvent.notifyOne(); } break; @@ -666,26 +667,30 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Initialize(); //start GKI, NCI task, NFC task - SyncEventGuard guard (sNfaEnableEvent); + { + SyncEventGuard guard (sNfaEnableEvent); + NFA_Init(); + NFA_BrcmInit (&devInitConfig, nfaBrcmInitCallback); - NFA_Init(); - NFA_BrcmInit (&devInitConfig, nfaBrcmInitCallback); + stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); + if (stat == NFA_STATUS_OK) + { + num = initializeGlobalAppLogLevel (); + CE_SetTraceLevel (num); + LLCP_SetTraceLevel (num); + NFC_SetTraceLevel (num); + NCI_SetTraceLevel (num); + RW_SetTraceLevel (num); + NFA_SetTraceLevel (num); + NFA_ChoSetTraceLevel (num); + NFA_P2pSetTraceLevel (num); + NFA_SnepSetTraceLevel (num); + sNfaEnableEvent.wait(); //wait for NFA command to finish + } + } - stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); if (stat == NFA_STATUS_OK) { - num = initializeGlobalAppLogLevel (); - CE_SetTraceLevel (num); - LLCP_SetTraceLevel (num); - NFC_SetTraceLevel (num); - NCI_SetTraceLevel (num); - RW_SetTraceLevel (num); - NFA_SetTraceLevel (num); - NFA_ChoSetTraceLevel (num); - NFA_P2pSetTraceLevel (num); - NFA_SnepSetTraceLevel (num); - sNfaEnableEvent.wait(); //wait for NFA command to finish - //sIsNfaEnabled indicates whether stack started successfully if (sIsNfaEnabled) { @@ -790,10 +795,10 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) stat = NFA_EnablePolling (tech_mask); if (stat == NFA_STATUS_OK) { - ALOGD ("%s: Waiting for sNfaEnableDisablePollingEvent", __FUNCTION__); + ALOGD ("%s: wait for enable event", __FUNCTION__); sDiscoveryEnabled = true; sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_START_EVT - ALOGD ("%s: Finished Waiting for sNfaEnableDisablePollingEvent", __FUNCTION__); + ALOGD ("%s: got enabled event", __FUNCTION__); } else { @@ -1592,11 +1597,10 @@ int register_com_android_nfc_NativeNfcManager (JNIEnv *e) *******************************************************************************/ void startRfDiscovery(bool isStart) { - SyncEventGuard guard (sNfaEnableDisablePollingEvent); tNFA_STATUS status = NFA_STATUS_FAILED; ALOGD ("%s: is start=%d", __FUNCTION__, isStart); - + SyncEventGuard guard (sNfaEnableDisablePollingEvent); status = isStart ? NFA_StartRfDiscovery () : NFA_StopRfDiscovery (); if (status == NFA_STATUS_OK) { diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index 25b9826..39ce2b1 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -173,7 +173,6 @@ static void switchBackTimerProc (union sigval) ** Returns: None ** *******************************************************************************/ -//called by NFA_READ_CPLT_EVT when NDEF message has been completely read void nativeNfcTag_doReadCompleted (tNFA_STATUS status) { ALOGD ("%s: status=0x%X; is reading=%u", __FUNCTION__, status, sIsReadingNdefMessage); @@ -260,10 +259,12 @@ static jbyteArray nativeNfcTag_doRead (JNIEnv *e, jobject o) if (sCheckNdefCurrentSize > 0) { - SyncEventGuard g (sReadEvent); - sIsReadingNdefMessage = true; - status = NFA_RwReadNDef (); - sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT + { + SyncEventGuard g (sReadEvent); + sIsReadingNdefMessage = true; + status = NFA_RwReadNDef (); + sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT + } sIsReadingNdefMessage = false; if (sReadDataLen > 0) //if stack actually read data from the tag @@ -539,18 +540,20 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) do { - SyncEventGuard g (sReconnectEvent); - gIsTagDeactivating = true; - sGotDeactivate = false; - if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) { - ALOGE ("%s: NFA_Deactivate failed, status = %d", __FUNCTION__, status); - break; - } + SyncEventGuard g (sReconnectEvent); + gIsTagDeactivating = true; + sGotDeactivate = false; + if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) + { + ALOGE ("%s: NFA_Deactivate failed, status = %d", __FUNCTION__, status); + break; + } - if (sReconnectEvent.wait (1000) == false) //if timeout occured - { - ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__); + if (sReconnectEvent.wait (1000) == false) //if timeout occurred + { + ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__); + } } if (! NfcTag::getInstance ().isActivated ()) @@ -561,23 +564,26 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) gIsTagDeactivating = false; - SyncEventGuard g2 (sReconnectEvent); - - sConnectWaitingForComplete = JNI_TRUE; - ALOGD ("%s: NFA_Select()", __FUNCTION__); - gIsSelectingRfInterface = true; - if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface))) { - ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status); - break; - } + SyncEventGuard g2 (sReconnectEvent); - sConnectOk = false; - if (sReconnectEvent.wait (1000) == false) //if timeout occured - { - ALOGE ("%s: wait response timeout", __FUNCTION__); - break; + sConnectWaitingForComplete = JNI_TRUE; + ALOGD ("%s: NFA_Select()", __FUNCTION__); + gIsSelectingRfInterface = true; + if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface))) + { + ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status); + break; + } + + sConnectOk = false; + if (sReconnectEvent.wait (1000) == false) //if timeout occured + { + ALOGE ("%s: wait response timeout", __FUNCTION__); + break; + } } + ALOGD("%s: done waiting on NFA_Select() sConnectOk=%d", __FUNCTION__, sConnectOk); if (! NfcTag::getInstance ().isActivated ()) { diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 3c46a02..1db7487 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -257,17 +257,19 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service if (sSnepServiceName.compare(serviceName) == 0) serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 - SyncEventGuard guard (pSrv->mRegServerEvent); - stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); - if (stat != NFA_STATUS_OK) { - ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); - removeServer (jniHandle); - return (false); + SyncEventGuard guard (pSrv->mRegServerEvent); + stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); + if (stat != NFA_STATUS_OK) + { + ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); + removeServer (jniHandle); + return (false); + } + ALOGD ("%s: wait for listen-completion event", fn); + // Wait for NFA_P2P_REG_SERVER_EVT + pSrv->mRegServerEvent.wait (); } - ALOGD ("%s: wait for listen-completion event", fn); - // Wait for NFA_P2P_REG_SERVER_EVT - pSrv->mRegServerEvent.wait (); if (pSrv->mNfaP2pServerHandle == NFA_HANDLE_INVALID) { @@ -567,9 +569,11 @@ bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) return (false); } - // Server does not call NFA_P2pDisconnect(), so unblock the accept() - SyncEventGuard guard (pSrv->mConnRequestEvent); - pSrv->mConnRequestEvent.notifyOne(); + { + // Server does not call NFA_P2pDisconnect(), so unblock the accept() + SyncEventGuard guard (pSrv->mConnRequestEvent); + pSrv->mConnRequestEvent.notifyOne(); + } nfaStat = NFA_P2pDeregister (pSrv->mNfaP2pServerHandle); if (nfaStat != NFA_STATUS_OK) @@ -741,19 +745,20 @@ bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* se // Save JNI Handle and try to connect to SNEP mJniHandleSendingNppViaSnep = jniHandle; - - if (NFA_SnepConnect (mSnepRegHandle, const_cast("urn:nfc:sn:snep")) == NFA_STATUS_OK) { SyncEventGuard guard (pClient->mSnepEvent); - pClient->mSnepEvent.wait(); - - // If the connect attempt failed, connection handle is invalid - if (pClient->mSnepConnHandle != NFA_HANDLE_INVALID) + if (NFA_SnepConnect (mSnepRegHandle, const_cast("urn:nfc:sn:snep")) == NFA_STATUS_OK) { - // return true, as if we were connected. - pClient->mClientConn.mRemoteMaxInfoUnit = 248; - pClient->mClientConn.mRemoteRecvWindow = 1; - return (true); + pClient->mSnepEvent.wait(); + + // If the connect attempt failed, connection handle is invalid + if (pClient->mSnepConnHandle != NFA_HANDLE_INVALID) + { + // return true, as if we were connected. + pClient->mClientConn.mRemoteMaxInfoUnit = 248; + pClient->mClientConn.mRemoteRecvWindow = 1; + return (true); + } } } mJniHandleSendingNppViaSnep = 0; @@ -812,22 +817,26 @@ bool PeerToPeer::createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* ser return (false); } - SyncEventGuard guard (pClient->mConnectingEvent); - pClient->mIsConnecting = true; - - if (serviceName) - nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle, - const_cast(serviceName), pClient->mClientConn.mMaxInfoUnit, - pClient->mClientConn.mRecvWindow); - else if (destinationSap) - nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap, - pClient->mClientConn.mMaxInfoUnit, pClient->mClientConn.mRecvWindow); + { + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mIsConnecting = true; + + if (serviceName) + nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle, + const_cast(serviceName), pClient->mClientConn.mMaxInfoUnit, + pClient->mClientConn.mRecvWindow); + else if (destinationSap) + nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap, + pClient->mClientConn.mMaxInfoUnit, pClient->mClientConn.mRecvWindow); + if (nfaStat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient); + pClient->mConnectingEvent.wait(); + } + } if (nfaStat == NFA_STATUS_OK) { - ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient); - pClient->mConnectingEvent.wait(); - if (pClient->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) { removeConn (jniHandle); @@ -1109,6 +1118,7 @@ bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 { ALOGD ("%s GKI_poolcount(2): %u GKI_poolfreecount(2): %u", fn, GKI_poolcount(2), GKI_poolfreecount(2)); + SyncEventGuard guard (pClient->mSnepEvent); nfaStat = NFA_SnepPut (pClient->mSnepConnHandle, pClient->mSnepNdefBufLen, pClient->mSnepNdefBuf); if (nfaStat != NFA_STATUS_OK) @@ -1119,8 +1129,6 @@ bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 pClient->mSnepNdefBuf = NULL; return (false); } - - SyncEventGuard guard (pClient->mSnepEvent); pClient->mSnepEvent.wait (); free (pClient->mSnepNdefBuf); @@ -1168,6 +1176,7 @@ bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 buff while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) { + //NFA_P2pReadData() is synchronous stat = NFA_P2pReadData (pConn->mNfaConnHandle, bufferLen, &actualDataLen2, buffer, &isMoreData); if ((stat == NFA_STATUS_OK) && (actualDataLen2 > 0)) //received some data { @@ -1831,8 +1840,8 @@ void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA { ALOGD ("%s NFA_SNEP_CONNECTED_EVT mJniHandleSendingNppViaSnep: %u ConnHandle: 0x%04x", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->connect.conn_handle); - pClient->mSnepConnHandle = eventData->connect.conn_handle; SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepConnHandle = eventData->connect.conn_handle; pClient->mSnepEvent.notifyOne(); } break; @@ -1863,9 +1872,8 @@ void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA else { ALOGD ("%s NFA_SNEP_DISC_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - pClient->mSnepConnHandle = NFA_HANDLE_INVALID; - SyncEventGuard guard (pClient->mSnepEvent); + pClient->mSnepConnHandle = NFA_HANDLE_INVALID; pClient->mSnepEvent.notifyOne(); } break; diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 76955f8..0bc86c8 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -1681,11 +1681,11 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len); if (eventData->registry.data_len >= 19 && ((eventData->registry.pipe == STATIC_PIPE_0x70) || (eventData->registry.pipe == STATIC_PIPE_0x71))) { + SyncEventGuard guard (sSecElem.mVerInfoEvent); // Oberthur OS version is in bytes 16,17, and 18 sSecElem.mVerInfo[0] = eventData->registry.reg_data[16]; sSecElem.mVerInfo[1] = eventData->registry.reg_data[17]; sSecElem.mVerInfo[2] = eventData->registry.reg_data[18]; - SyncEventGuard guard (sSecElem.mVerInfoEvent); sSecElem.mVerInfoEvent.notifyOne (); } break; diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h index 5ab5d43..146b3ce 100644 --- a/nci/jni/SyncEvent.h +++ b/nci/jni/SyncEvent.h @@ -28,7 +28,6 @@ public: *******************************************************************************/ ~SyncEvent () { - mMutex.unlock (); } @@ -59,7 +58,6 @@ public: void wait () { mCondVar.wait (mMutex); - end (); } @@ -76,7 +74,6 @@ public: bool wait (long millisec) { bool retVal = mCondVar.wait (mMutex, millisec); - end (); return retVal; } @@ -93,7 +90,6 @@ public: void notifyOne () { mCondVar.notifyOne (); - end (); } -- cgit v1.1 From 8e9cdd7891bc1d6589b6d51b7c39efc87a64ba5e Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Fri, 17 Aug 2012 12:36:09 -0400 Subject: Create JavaClassConstants.h to store some global names Create JavaClassConstants.h to store some global names Change-Id: I918d9e8f6db646f637cddbebbc2c4e5c5495623d --- nci/jni/JavaClassConstants.h | 36 ++++++++++++++++++++++++++++++ nci/jni/NativeLlcpConnectionlessSocket.cpp | 4 +--- nci/jni/NativeLlcpServiceSocket.cpp | 5 +---- nci/jni/NativeLlcpSocket.cpp | 4 +--- nci/jni/NativeNfcManager.cpp | 1 + nci/jni/NativeNfcTag.cpp | 2 +- nci/jni/NativeP2pDevice.cpp | 4 +--- nci/jni/NativeSecureElement.cpp | 2 +- nci/jni/NfcTag.cpp | 7 +----- nci/jni/PeerToPeer.cpp | 3 +-- nci/jni/SecureElement.cpp | 13 +++-------- 11 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 nci/jni/JavaClassConstants.h diff --git a/nci/jni/JavaClassConstants.h b/nci/jni/JavaClassConstants.h new file mode 100644 index 0000000..fb71757 --- /dev/null +++ b/nci/jni/JavaClassConstants.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + + +namespace android +{ + extern jmethodID gCachedNfcManagerNotifyNdefMessageListeners; + extern jmethodID gCachedNfcManagerNotifyTransactionListeners; + extern jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; + extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; + extern jmethodID gCachedNfcManagerNotifySeFieldActivated; + extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated; + + extern const char* gNativeP2pDeviceClassName; + extern const char* gNativeLlcpServiceSocketClassName; + extern const char* gNativeLlcpConnectionlessSocketClassName; + extern const char* gNativeLlcpSocketClassName; + extern const char* gNativeNfcTagClassName; + extern const char* gNativeNfcManagerClassName; + extern const char* gNativeNfcSecureElementClassName; +} diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp index 2c4618f..a278844 100644 --- a/nci/jni/NativeLlcpConnectionlessSocket.cpp +++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp @@ -19,6 +19,7 @@ #include #include "OverrideLog.h" #include "NfcJniUtil.h" +#include "JavaClassConstants.h" extern "C" { #include "nfa_api.h" @@ -30,9 +31,6 @@ namespace android { -extern char* gNativeLlcpConnectionlessSocketClassName; - - /***************************************************************************** ** ** private variables and functions diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp index 7572690..ac00f61 100644 --- a/nci/jni/NativeLlcpServiceSocket.cpp +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -19,6 +19,7 @@ #include "NfcJniUtil.h" #include "NfcAdaptation.h" #include "PeerToPeer.h" +#include "JavaClassConstants.h" extern "C" { #include "nfa_api.h" @@ -30,10 +31,6 @@ namespace android { -extern char* gNativeLlcpServiceSocketClassName; -extern char* gNativeLlcpSocketClassName; - - /******************************************************************************* ** ** Function: nativeLlcpServiceSocket_doAccept diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp index f0f0d3d..55a4a76 100644 --- a/nci/jni/NativeLlcpSocket.cpp +++ b/nci/jni/NativeLlcpSocket.cpp @@ -16,15 +16,13 @@ */ #include "OverrideLog.h" #include "PeerToPeer.h" +#include "JavaClassConstants.h" namespace android { -extern char* gNativeLlcpSocketClassName; - - /******************************************************************************* ** ** Function: nativeLlcpSocket_doConnect diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 69a9c3f..20bdd96 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -26,6 +26,7 @@ #include "NfcTag.h" #include "config.h" #include "PowerSwitch.h" +#include "JavaClassConstants.h" extern "C" { diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index 39ce2b1..a4d2ec7 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "Mutex.h" #include "IntervalTimer.h" +#include "JavaClassConstants.h" extern "C" { @@ -36,7 +37,6 @@ extern "C" namespace android { extern nfc_jni_native_data* getNative(JNIEnv *e, jobject o); - extern char* gNativeNfcTagClassName; extern bool nfcManager_isNfcActive(); extern int gGeneralTransceiveTimeout; } diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp index 2f06b96..216edb1 100644 --- a/nci/jni/NativeP2pDevice.cpp +++ b/nci/jni/NativeP2pDevice.cpp @@ -17,15 +17,13 @@ #include "OverrideLog.h" #include "NfcJniUtil.h" +#include "JavaClassConstants.h" namespace android { -extern char* gNativeP2pDeviceClassName; - - static jboolean nativeP2pDeviceDoConnect (JNIEnv* e, jobject o) { ALOGD ("%s", __FUNCTION__); diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp index 55bece8..7054b26 100755 --- a/nci/jni/NativeSecureElement.cpp +++ b/nci/jni/NativeSecureElement.cpp @@ -16,6 +16,7 @@ */ #include "OverrideLog.h" #include "SecureElement.h" +#include "JavaClassConstants.h" #include "nfa_brcm_api.h" @@ -25,7 +26,6 @@ namespace android extern void com_android_nfc_NfcManager_disableDiscovery (JNIEnv* e, jobject o); extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode); -extern char* gNativeNfcSecureElementClassName; extern int gGeneralTransceiveTimeout; diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp index 9d629a2..35df2f0 100755 --- a/nci/jni/NfcTag.cpp +++ b/nci/jni/NfcTag.cpp @@ -10,18 +10,13 @@ *****************************************************************************/ #include "OverrideLog.h" #include "NfcTag.h" +#include "JavaClassConstants.h" extern "C" { #include "rw_int.h" } -namespace android -{ - extern jmethodID gCachedNfcManagerNotifyNdefMessageListeners; -} - - /******************************************************************************* ** ** Function: NfcTag diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 1db7487..56174d5 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -13,11 +13,10 @@ #include "NfcJniUtil.h" #include "llcp_defs.h" #include "config.h" +#include "JavaClassConstants.h" namespace android { - extern jmethodID gCachedNfcManagerNotifyLlcpLinkActivation; - extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; extern void nativeNfcTag_registerNdefTypeHandler (); extern void nativeNfcTag_deregisterNdefTypeHandler (); } diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 0bc86c8..8847db7 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -17,14 +17,7 @@ #include "PowerSwitch.h" #include "HostAidRouter.h" #include "nfa_vs_brcm_api.h" - - -namespace android -{ - extern jmethodID gCachedNfcManagerNotifyTransactionListeners; - extern jmethodID gCachedNfcManagerNotifySeFieldActivated; - extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated; -} +#include "JavaClassConstants.h" /***************************************************************************** @@ -190,7 +183,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) SyncEventGuard guard (mHciRegisterEvent); - nfaStat = NFA_HciRegister ("brcm_jni", nfaHciCallback, TRUE); + nfaStat = NFA_HciRegister (const_cast("brcm_jni"), nfaHciCallback, TRUE); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); @@ -229,7 +222,7 @@ void SecureElement::finalize () NFA_EeDeregister (nfaEeCallback); if (mNfaHciHandle != NFA_HANDLE_INVALID) - NFA_HciDeregister ("brcm_jni"); + NFA_HciDeregister (const_cast("brcm_jni")); mNfaHciHandle = NFA_HANDLE_INVALID; mNativeData = NULL; -- cgit v1.1 From f340f1a071a54c6ea4644fcef45c784a9be3c19a Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Tue, 28 Aug 2012 13:08:20 -0400 Subject: Upgrade to stack NFA_MI_1.03.36 Change-Id: I79510a45e8a552626f0473000e23d0fc6888ee33 --- nci/jni/NativeNfcManager.cpp | 18 +++++++++++------- nci/jni/SecureElement.cpp | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 20bdd96..ff61cfe 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -133,7 +133,7 @@ static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); static bool isPeerToPeer (tNFA_ACTIVATED& activated); static void startRfDiscovery (bool isStart); -static void nfaBrcmInitCallback (UINT32 brcm_hw_id); +static void nfaBrcmInitCallback (UINT32 brcm_hw_id, UINT8 nvm_type); ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// @@ -671,6 +671,14 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) { SyncEventGuard guard (sNfaEnableEvent); NFA_Init(); + + // Initialize the Crystal Frequency if configured. + if (GetNumValue((char*)NAME_XTAL_FREQUENCY, &devInitConfig.xtal_freq, sizeof(devInitConfig.xtal_freq))) + { + ALOGD("%s: setting XTAL Frequency=%d", __FUNCTION__, devInitConfig.xtal_freq); + devInitConfig.flags |= BRCM_DEV_INIT_FLAGS_SET_XTAL_FREQ; + } + NFA_BrcmInit (&devInitConfig, nfaBrcmInitCallback); stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); @@ -733,10 +741,6 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) NFA_SetMultiTechRsp(TRUE); - // if this value is not set or set and non-zero, enable sleep mode. - if (!GetNumValue(NAME_NFA_DM_ENABLE_SLEEP, &num, sizeof(num)) || (num != 0)) - NFA_EnableSnoozeMode(); - // Do custom NFCA startup configuration. doStartupConfig(); goto TheEnd; @@ -1706,9 +1710,9 @@ bool nfcManager_isNfcActive() ** Returns: None. ** *******************************************************************************/ -void nfaBrcmInitCallback (UINT32 brcm_hw_id) +void nfaBrcmInitCallback (UINT32 brcm_hw_id, UINT8 nvm_type) { - ALOGD ("%s: enter; brcm_hw_id=0x%lX", __FUNCTION__, brcm_hw_id); + ALOGD ("%s: enter; brcm_hw_id=0x%lX; nvm_type=0x%X", __FUNCTION__, brcm_hw_id, nvm_type); nfa_app_post_nci_reset (brcm_hw_id); } diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 8847db7..1d52955 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -811,9 +811,9 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* mActualResponseSize = 0; memset (mResponseData, 0, sizeof(mResponseData)); if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71)) - nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, 0); else - nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData); + nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, 0); if (nfaStat == NFA_STATUS_OK) { -- cgit v1.1 From db216e63dad45973ff4992098229208a518d658f Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 4 Sep 2012 11:17:52 +0200 Subject: Add FLAG_ACTIVITY_NEW_TASK to Beam Handover intent. Bug: 6925612 Change-Id: I37f49a150c4fc1763b2121e46fedf79d662b0a2b --- src/com/android/nfc/handover/HandoverManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index f77f780..8983389 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -390,7 +390,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, notBuilder.setContentText(mContext.getString(R.string.beam_touch_to_view)); Intent viewIntent = buildViewIntent(); - PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, 0); + PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, + Intent.FLAG_ACTIVITY_NEW_TASK); notBuilder.setContentIntent(contentIntent); -- cgit v1.1 From 01bd745d05c678e5ab768b7972dcbe7519be2149 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Wed, 5 Sep 2012 11:18:29 -0400 Subject: Remove "brcm" in names BLTH01642677. Remove "brcm" in names. Change-Id: Ic3a08abfeb2808d2a0b01402a76d9864b099ef49 --- nci/jni/NativeLlcpServiceSocket.cpp | 8 +++--- nci/jni/NativeLlcpSocket.cpp | 14 +++++------ nci/jni/NativeNfcManager.cpp | 8 +++--- nci/jni/PeerToPeer.cpp | 40 ++++++++++++++--------------- nci/jni/PeerToPeer.h | 50 ++++++++++++++++++------------------- nci/jni/PowerSwitch.h | 1 - nci/jni/SecureElement.cpp | 3 ++- nci/jni/SecureElement.h | 1 - 8 files changed, 62 insertions(+), 63 deletions(-) diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp index ac00f61..c4a655e 100644 --- a/nci/jni/NativeLlcpServiceSocket.cpp +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -50,13 +50,13 @@ static jobject nativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jobject clientSocket = NULL; jclass clsNativeLlcpSocket = NULL; jfieldID f = 0; - tBRCM_JNI_HANDLE serverHandle; //handle of the local server + PeerToPeer::tJNI_HANDLE serverHandle; //handle of the local server bool stat = false; - tBRCM_JNI_HANDLE connHandle = PeerToPeer::getInstance().getNewJniHandle (); + PeerToPeer::tJNI_HANDLE connHandle = PeerToPeer::getInstance().getNewJniHandle (); ALOGD ("%s: enter", __FUNCTION__); - serverHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e, o); + serverHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e, o); stat = PeerToPeer::getInstance().accept (serverHandle, connHandle, miu, rw); @@ -114,7 +114,7 @@ TheEnd: static jboolean nativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o) { ALOGD ("%s: enter", __FUNCTION__); - tBRCM_JNI_HANDLE jniServerHandle = 0; + PeerToPeer::tJNI_HANDLE jniServerHandle = 0; bool stat = false; jniServerHandle = nfc_jni_get_nfc_socket_handle (e, o); diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp index 55a4a76..f5daff0 100644 --- a/nci/jni/NativeLlcpSocket.cpp +++ b/nci/jni/NativeLlcpSocket.cpp @@ -42,7 +42,7 @@ static jboolean nativeLlcpSocket_doConnect (JNIEnv* e, jobject o, jint nSap) ALOGD ("%s: enter; sap=%d", __FUNCTION__, nSap); - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, nSap); @@ -72,7 +72,7 @@ static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn) bool stat = false; jboolean retVal = JNI_FALSE; - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* @@ -105,7 +105,7 @@ static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o) bool stat = false; jboolean retVal = JNI_FALSE; - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); stat = PeerToPeer::getInstance().disconnectConnOriented (jniHandle); @@ -134,7 +134,7 @@ static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data) uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (data); bool stat = false; - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); stat = PeerToPeer::getInstance().send (jniHandle, dataBuffer, dataBufferLen); @@ -166,7 +166,7 @@ static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuff bool stat = false; jint retval = 0; - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); stat = PeerToPeer::getInstance().receive (jniHandle, dataBuffer, dataBufferLen, actualLen); @@ -199,7 +199,7 @@ static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o) ALOGD ("%s: enter", __FUNCTION__); bool stat = false; - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); jint miu = 0; miu = PeerToPeer::getInstance().getRemoteMaxInfoUnit (jniHandle); @@ -226,7 +226,7 @@ static jint nativeLlcpSocket_doGetRemoteSocketRW (JNIEnv* e, jobject o) bool stat = false; jint rw = 0; - tBRCM_JNI_HANDLE jniHandle = (tBRCM_JNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); + PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o); rw = PeerToPeer::getInstance().getRemoteRecvWindow (jniHandle); diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index ff61cfe..da9b242 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -42,7 +42,7 @@ extern "C" extern UINT8 *p_nfa_dm_lptd_cfg; extern UINT8 *p_nfa_dm_start_up_cfg; extern const UINT8 nfca_version_string []; -extern "C" void nfa_app_post_nci_reset (UINT32 brcm_hw_id); +extern "C" void downloadFirmwarePatchFile (UINT32 brcm_hw_id); namespace android { extern bool gIsTagDeactivating; @@ -940,7 +940,7 @@ static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject o, jint jobject serviceSocket = NULL; jclass clsNativeLlcpServiceSocket = NULL; jfieldID f = 0; - tBRCM_JNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle (); + PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle (); const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char* std::string serviceName2 (serviceName); @@ -1091,7 +1091,7 @@ static jobject nfcManager_doCreateLlcpSocket (JNIEnv* e, jobject o, jint nSap, j jobject clientSocket = NULL; jclass clsNativeLlcpSocket; jfieldID f; - tBRCM_JNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle (); + PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle (); bool stat = false; stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw); @@ -1713,7 +1713,7 @@ bool nfcManager_isNfcActive() void nfaBrcmInitCallback (UINT32 brcm_hw_id, UINT8 nvm_type) { ALOGD ("%s: enter; brcm_hw_id=0x%lX; nvm_type=0x%X", __FUNCTION__, brcm_hw_id, nvm_type); - nfa_app_post_nci_reset (brcm_hw_id); + downloadFirmwarePatchFile (brcm_hw_id); } diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 56174d5..02aded1 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -142,7 +142,7 @@ P2pServer *PeerToPeer::findServer (tNFA_HANDLE nfaP2pServerHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pServer *PeerToPeer::findServer (tBRCM_JNI_HANDLE jniHandle) +P2pServer *PeerToPeer::findServer (tJNI_HANDLE jniHandle) { for (int i = 0; i < sMax; i++) { @@ -192,7 +192,7 @@ P2pServer *PeerToPeer::findServer (const char *serviceName) ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *serviceName) +bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName) { static const char fn [] = "PeerToPeer::registerServer"; ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle); @@ -294,7 +294,7 @@ bool PeerToPeer::registerServer (tBRCM_JNI_HANDLE jniHandle, const char *service ** Returns: None ** *******************************************************************************/ -void PeerToPeer::removeServer (tBRCM_JNI_HANDLE jniHandle) +void PeerToPeer::removeServer (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::removeServer"; @@ -465,7 +465,7 @@ void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEA ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow) +bool PeerToPeer::accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow) { static const char fn [] = "PeerToPeer::accept"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; @@ -555,7 +555,7 @@ bool PeerToPeer::accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE conn ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) +bool PeerToPeer::deregisterServer (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::deregisterServer"; ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle); @@ -599,7 +599,7 @@ bool PeerToPeer::deregisterServer (tBRCM_JNI_HANDLE jniHandle) ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) +bool PeerToPeer::createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) { static const char fn [] = "PeerToPeer::createClient"; int i = 0; @@ -654,7 +654,7 @@ bool PeerToPeer::createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) ** Returns: None ** *******************************************************************************/ -void PeerToPeer::removeConn(tBRCM_JNI_HANDLE jniHandle) +void PeerToPeer::removeConn(tJNI_HANDLE jniHandle) { static const char fn[] = "PeerToPeer::removeConn"; int ii = 0, jj = 0; @@ -720,7 +720,7 @@ void PeerToPeer::removeConn(tBRCM_JNI_HANDLE jniHandle) ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName) +bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName) { static const char fn [] = "PeerToPeer::connectConnOriented"; ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName); @@ -781,7 +781,7 @@ bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* se ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap) +bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap) { static const char fn [] = "PeerToPeer::connectConnOriented"; ALOGD ("%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap); @@ -803,7 +803,7 @@ bool PeerToPeer::connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinat ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap) +bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap) { static const char fn [] = "PeerToPeer::createDataLinkConn"; ALOGD ("%s: enter", fn); @@ -886,7 +886,7 @@ P2pClient *PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pClient *PeerToPeer::findClient (tBRCM_JNI_HANDLE jniHandle) +P2pClient *PeerToPeer::findClient (tJNI_HANDLE jniHandle) { for (int i = 0; i < sMax; i++) { @@ -969,7 +969,7 @@ NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -NfaConn *PeerToPeer::findConnection (tBRCM_JNI_HANDLE jniHandle) +NfaConn *PeerToPeer::findConnection (tJNI_HANDLE jniHandle) { int ii = 0, jj = 0; @@ -1012,7 +1012,7 @@ NfaConn *PeerToPeer::findConnection (tBRCM_JNI_HANDLE jniHandle) ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) +bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) { static const char fn [] = "PeerToPeer::send"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; @@ -1068,7 +1068,7 @@ bool PeerToPeer::send (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferL ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 dataLen) +bool PeerToPeer::sendViaSnep (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 dataLen) { static const char fn [] = "PeerToPeer::sendViaSnep"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; @@ -1152,7 +1152,7 @@ bool PeerToPeer::sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) +bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) { static const char fn [] = "PeerToPeer::receive"; ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); @@ -1243,7 +1243,7 @@ bool PeerToPeer::feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actua ** Returns: True if ok. ** *******************************************************************************/ -bool PeerToPeer::disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle) +bool PeerToPeer::disconnectConnOriented (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::disconnectConnOriented"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; @@ -1306,7 +1306,7 @@ bool PeerToPeer::disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle) ** Returns: Peer's max information unit. ** *******************************************************************************/ -UINT16 PeerToPeer::getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle) +UINT16 PeerToPeer::getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit"; NfaConn *pConn = NULL; @@ -1331,7 +1331,7 @@ UINT16 PeerToPeer::getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle) ** Returns: Peer's receive window size. ** *******************************************************************************/ -UINT8 PeerToPeer::getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle) +UINT8 PeerToPeer::getRemoteRecvWindow (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::getRemoteRecvWindow"; ALOGD ("%s: client jni handle: %u", fn, jniHandle); @@ -2010,9 +2010,9 @@ void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventD ** Returns: A new JNI handle. ** *******************************************************************************/ -tBRCM_JNI_HANDLE PeerToPeer::getNewJniHandle () +PeerToPeer::tJNI_HANDLE PeerToPeer::getNewJniHandle () { - tBRCM_JNI_HANDLE newHandle = 0; + tJNI_HANDLE newHandle = 0; mNewJniHandleMutex.lock (); newHandle = mNextJniHandle++; diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index d689298..2921492 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -22,7 +22,6 @@ class P2pServer; class P2pClient; class NfaConn; #define MAX_NFA_CONNS_PER_SERVER 5 -typedef unsigned int tBRCM_JNI_HANDLE; /***************************************************************************** @@ -35,6 +34,7 @@ typedef unsigned int tBRCM_JNI_HANDLE; class PeerToPeer { public: + typedef unsigned int tJNI_HANDLE; /******************************************************************************* @@ -138,7 +138,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool registerServer (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); + bool registerServer (tJNI_HANDLE jniHandle, const char* serviceName); /******************************************************************************* @@ -150,7 +150,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool deregisterServer (tBRCM_JNI_HANDLE jniHandle); + bool deregisterServer (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -166,7 +166,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool accept (tBRCM_JNI_HANDLE serverJniHandle, tBRCM_JNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow); + bool accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow); /******************************************************************************* @@ -181,7 +181,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool createClient (tBRCM_JNI_HANDLE jniHandle, UINT16 miu, UINT8 rw); + bool createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw); /******************************************************************************* @@ -195,7 +195,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, const char* serviceName); + bool connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName); /******************************************************************************* @@ -209,7 +209,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool connectConnOriented (tBRCM_JNI_HANDLE jniHandle, UINT8 destinationSap); + bool connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap); /******************************************************************************* @@ -224,7 +224,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool send (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen); + bool send (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen); /******************************************************************************* @@ -240,7 +240,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool receive (tBRCM_JNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); + bool receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); /******************************************************************************* @@ -253,7 +253,7 @@ public: ** Returns: True if ok. ** *******************************************************************************/ - bool disconnectConnOriented (tBRCM_JNI_HANDLE jniHandle); + bool disconnectConnOriented (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -266,7 +266,7 @@ public: ** Returns: Peer's max information unit. ** *******************************************************************************/ - UINT16 getRemoteMaxInfoUnit (tBRCM_JNI_HANDLE jniHandle); + UINT16 getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -279,7 +279,7 @@ public: ** Returns: Peer's receive window size. ** *******************************************************************************/ - UINT8 getRemoteRecvWindow (tBRCM_JNI_HANDLE jniHandle); + UINT8 getRemoteRecvWindow (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -329,7 +329,7 @@ public: ** Returns: A new JNI handle. ** *******************************************************************************/ - tBRCM_JNI_HANDLE getNewJniHandle (); + tJNI_HANDLE getNewJniHandle (); private: @@ -340,14 +340,14 @@ private: UINT16 mRemoteWKS; // Peer's well known services bool mIsP2pListening; // If P2P listening is enabled or not tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask - tBRCM_JNI_HANDLE mJniHandleSendingNppViaSnep; + tJNI_HANDLE mJniHandleSendingNppViaSnep; tNFA_HANDLE mSnepRegHandle; - tBRCM_JNI_HANDLE mRcvFakeNppJniHandle; + tJNI_HANDLE mRcvFakeNppJniHandle; UINT8 *mNppFakeOutBuffer; UINT32 mNppTotalLen; UINT32 mNppReadSoFar; tNFA_HANDLE mNdefTypeHandlerHandle; - tBRCM_JNI_HANDLE mNextJniHandle; + tJNI_HANDLE mNextJniHandle; P2pServer *mServers [sMax]; P2pClient *mClients [sMax]; @@ -437,7 +437,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pServer *findServer (tBRCM_JNI_HANDLE jniHandle); + P2pServer *findServer (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -463,7 +463,7 @@ private: ** Returns: None ** *******************************************************************************/ - void removeServer (tBRCM_JNI_HANDLE jniHandle); + void removeServer (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -476,7 +476,7 @@ private: ** Returns: None ** *******************************************************************************/ - void removeConn (tBRCM_JNI_HANDLE jniHandle); + void removeConn (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -491,7 +491,7 @@ private: ** Returns: True if ok. ** *******************************************************************************/ - bool createDataLinkConn (tBRCM_JNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap); + bool createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap); /******************************************************************************* @@ -517,7 +517,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pClient *findClient (tBRCM_JNI_HANDLE jniHandle); + P2pClient *findClient (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -556,7 +556,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - NfaConn *findConnection (tBRCM_JNI_HANDLE jniHandle); + NfaConn *findConnection (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -571,7 +571,7 @@ private: ** Returns: True if ok. ** *******************************************************************************/ - bool sendViaSnep (tBRCM_JNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen); + bool sendViaSnep (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen); /******************************************************************************* @@ -601,7 +601,7 @@ class NfaConn { public: tNFA_HANDLE mNfaConnHandle; // NFA handle of the P2P connection - tBRCM_JNI_HANDLE mJniHandle; // JNI handle of the P2P connection + PeerToPeer::tJNI_HANDLE mJniHandle; // JNI handle of the P2P connection UINT16 mMaxInfoUnit; UINT8 mRecvWindow; UINT16 mRemoteMaxInfoUnit; @@ -635,7 +635,7 @@ class P2pServer { public: tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server - tBRCM_JNI_HANDLE mJniHandle; // JNI Handle + PeerToPeer::tJNI_HANDLE mJniHandle; // JNI Handle SyncEvent mRegServerEvent; // for NFA_P2pRegisterServer() SyncEvent mConnRequestEvent; // for accept() std::string mServiceName; diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h index 896133e..2e6b604 100755 --- a/nci/jni/PowerSwitch.h +++ b/nci/jni/PowerSwitch.h @@ -10,7 +10,6 @@ *****************************************************************************/ #pragma once #include "nfa_api.h" -#include "nfa_brcm_api.h" #include "SyncEvent.h" diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 1d52955..e4d9400 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -17,6 +17,7 @@ #include "PowerSwitch.h" #include "HostAidRouter.h" #include "nfa_vs_brcm_api.h" +#include "nfa_brcm_api.h" #include "JavaClassConstants.h" @@ -183,7 +184,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) SyncEventGuard guard (mHciRegisterEvent); - nfaStat = NFA_HciRegister (const_cast("brcm_jni"), nfaHciCallback, TRUE); + nfaStat = NFA_HciRegister (const_cast("nfc_jni"), nfaHciCallback, TRUE); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index ea1f568..65e779e 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -16,7 +16,6 @@ #include "RouteDataSet.h" extern "C" { - #include "nfa_brcm_api.h" #include "nfa_ee_api.h" #include "nfa_hci_api.h" #include "nfa_hci_defs.h" -- cgit v1.1 From 08030f1c2a13eca1acc67b9d0763a3b6a2706f02 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Wed, 5 Sep 2012 11:34:14 -0400 Subject: handle NACK, ACK for Mifare Ultralight BLTH01652900: During trasceive operation for Mifare Ultralight, handle NACK and ACK responses properly Bug: 7047415 Change-Id: I778a2bbbcd3fff47b0da73ec37d76bf81708d931 --- nci/jni/NativeNfcTag.cpp | 12 ++++++++++++ nci/jni/NfcTag.cpp | 30 ++++++++++++++++++++++++++++++ nci/jni/NfcTag.h | 18 +++++++++++++++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index a4d2ec7..f4b345d 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -870,6 +870,18 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da } ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen); + + if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) && + natTag.isT2tNackResponse (sTransceiveData, sTransceiveDataLen)) + { + if (targetLost) + { + ALOGD ("%s: t2t nack", __FUNCTION__); + *targetLost = 1; //causes NFC service to throw TagLostException + } + break; + } + if (sTransceiveDataLen) { // marshall data to java for return diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp index 35df2f0..ed140f6 100755 --- a/nci/jni/NfcTag.cpp +++ b/nci/jni/NfcTag.cpp @@ -1165,6 +1165,36 @@ bool NfcTag::isMifareUltralight () /******************************************************************************* ** +** Function: isT2tNackResponse +** +** Description: Whether the response is a T2T NACK response. +** See NFC Digital Protocol Technical Specification (2010-11-17). +** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ). +** response: buffer contains T2T response. +** responseLen: length of the response. +** +** Returns: True if the response is NACK +** +*******************************************************************************/ +bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen) +{ + static const char fn [] = "NfcTag::isT2tNackResponse"; + bool isNack = false; + + if (responseLen == 1) + { + if (response[0] == 0xA) + isNack = false; //an ACK response, so definitely not a NACK + else + isNack = true; //assume every value is a NACK + } + ALOGD ("%s: return %u", fn, isNack); + return isNack; +} + + +/******************************************************************************* +** ** Function: connectionEventHandler ** ** Description: Handle connection-related events. diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h index a692ddd..276a649 100755 --- a/nci/jni/NfcTag.h +++ b/nci/jni/NfcTag.h @@ -172,10 +172,26 @@ public: *******************************************************************************/ bool isMifareUltralight (); + + /******************************************************************************* + ** + ** Function: isT2tNackResponse + ** + ** Description: Whether the response is a T2T NACK response. + ** See NFC Digital Protocol Technical Specification (2010-11-17). + ** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ). + ** response: buffer contains T2T response. + ** responseLen: length of the response. + ** + ** Returns: True if the response is NACK + ** + *******************************************************************************/ + bool isT2tNackResponse (const UINT8* response, UINT32 responseLen); + private: nfc_jni_native_data* mNativeData; bool mIsActivated; - tNFC_PROTOCOL mProtocol; + tNFC_PROTOCOL mProtocol; int mtT1tMaxMessageSize; //T1T max NDEF message size tNFA_STATUS mReadCompletedStatus; tNFC_RF_TECH_PARAMS mTechParams [MAX_NUM_TECHNOLOGY]; //array of technology parameters -- cgit v1.1 From 7e5bdc93fb55d2090c4b32bff811abf4c39b2e52 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Wed, 5 Sep 2012 11:30:46 -0400 Subject: correctly handle P2P congestion event Correctly handle NFA_P2P_CONGEST_EVT to prevent race condition. Change-Id: If255ade96867d45b2a7cff1cb3d6e4cbc2d883d3 --- nci/jni/PeerToPeer.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 02aded1..fdfa30c 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -1033,17 +1033,20 @@ bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) return (sendViaSnep(jniHandle, buffer, bufferLen)); } - nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); - - while (nfaStat == NFA_STATUS_CONGESTED) + while (true) { SyncEventGuard guard (pConn->mCongEvent); - pConn->mCongEvent.wait (); + nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + if (nfaStat == NFA_STATUS_CONGESTED) + pConn->mCongEvent.wait (); //wait for NFA_P2P_CONGEST_EVT + else + break; - if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) + if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) //peer already disconnected + { + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: peer disconnected", fn); return (false); - - nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + } } if (nfaStat == NFA_STATUS_OK) @@ -1629,9 +1632,11 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev { ALOGD ("%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, eventData->congest.handle, eventData->congest.is_congested); - - SyncEventGuard guard (pConn->mCongEvent); - pConn->mCongEvent.notifyOne(); + if (eventData->congest.is_congested == FALSE) + { + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } } break; -- cgit v1.1 From 3463d49a81556279bb0c4c74d9f4c9fd49ee61af Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Wed, 5 Sep 2012 11:37:08 -0400 Subject: Correct spelling. Change-Id: Ie747c06a0a5161ad5479f93cbc56e482ed7da33c --- nci/jni/NativeNfcManager.cpp | 4 ++-- nci/jni/NativeNfcTag.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index da9b242..14e9cb9 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -47,7 +47,7 @@ namespace android { extern bool gIsTagDeactivating; extern bool gIsSelectingRfInterface; - extern void nativeNfcTag_doTranseiveStatus (uint8_t * buf, uint32_t buflen); + extern void nativeNfcTag_doTransceiveStatus (uint8_t * buf, uint32_t buflen); extern void nativeNfcTag_doConnectStatus (jboolean is_connect_ok); extern void nativeNfcTag_doDeactivateStatus (int status); extern void nativeNfcTag_doWriteStatus (jboolean is_write_ok); @@ -344,7 +344,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat case NFA_DATA_EVT: // Data message received (for non-NDEF reads) ALOGD("%s: NFA_DATA_EVT: len = %d", __FUNCTION__, eventData->data.len); - nativeNfcTag_doTranseiveStatus(eventData->data.p_data,eventData->data.len); + nativeNfcTag_doTransceiveStatus(eventData->data.p_data,eventData->data.len); break; case NFA_SELECT_CPLT_EVT: // Select completed diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index f4b345d..b4b517b 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -726,7 +726,7 @@ TheEnd: /******************************************************************************* ** -** Function: nativeNfcTag_doTranseiveStatus +** Function: nativeNfcTag_doTransceiveStatus ** ** Description: Receive the completion status of transceive operation. ** buf: Contains tag's response. @@ -735,7 +735,7 @@ TheEnd: ** Returns: None ** *******************************************************************************/ -void nativeNfcTag_doTranseiveStatus (uint8_t* buf, uint32_t bufLen) +void nativeNfcTag_doTransceiveStatus (uint8_t* buf, uint32_t bufLen) { ALOGD ("%s: data len=%d, waiting for transceive: %d", __FUNCTION__, bufLen, sWaitingForTransceive); if (!sWaitingForTransceive) -- cgit v1.1 From cdf5b0e0c3cdd1b60a212fd4df510fb1e50bcbe5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 6 Sep 2012 10:21:54 +0200 Subject: Remove old NPP->SNEP redirect code. This code was used when Android did not support SNEP natively yet. The current Android behavior is to automatically try SNEP first, then fall back to NPP. Change-Id: Ifb1df3a5439cc1a7b939b4ae1dc70135d9c63a25 --- nci/jni/PeerToPeer.cpp | 413 +------------------------------------------------ nci/jni/PeerToPeer.h | 42 ----- 2 files changed, 4 insertions(+), 451 deletions(-) diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index fdfa30c..bf18df5 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -24,7 +24,6 @@ namespace android PeerToPeer PeerToPeer::sP2p; const std::string PeerToPeer::sSnepServiceName ("urn:nfc:sn:snep"); -const std::string PeerToPeer::sNppServiceName ("com.android.npp"); /******************************************************************************* @@ -43,13 +42,6 @@ PeerToPeer::PeerToPeer () | NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE), - mJniHandleSendingNppViaSnep (0), - mSnepRegHandle (NFA_HANDLE_INVALID), - mRcvFakeNppJniHandle (0), - mNppFakeOutBuffer (NULL), - mNppTotalLen (0), - mNppReadSoFar (0), - mNdefTypeHandlerHandle (NFA_HANDLE_INVALID), mNextJniHandle (1) { unsigned long num = 0; @@ -338,10 +330,6 @@ void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIV //no longer need to receive NDEF message from a tag android::nativeNfcTag_deregisterNdefTypeHandler (); - //register a type handler in case we need to send NDEF messages received from SNEP through NPP - mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; - NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *)"", 0, ndefTypeCallback); - mRemoteWKS = activated.remote_wks; nat->vm->AttachCurrentThread (&e, NULL); @@ -442,10 +430,6 @@ void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEA nat->vm->DetachCurrentThread (); - //PeerToPeer no longer needs to handle NDEF data event - NFA_DeregisterNDefTypeHandler (mNdefTypeHandlerHandle); - mNdefTypeHandlerHandle = NFA_HANDLE_INVALID; - //let the tag-reading code handle NDEF data event android::nativeNfcTag_registerNdefTypeHandler (); ALOGD ("%s: exit", fn); @@ -512,16 +496,6 @@ bool PeerToPeer::accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); } - // If we had gotten a message via SNEP, fake it out to be for NPP - if (mRcvFakeNppJniHandle == serverJniHandle) - { - ALOGD ("%s: server jni handle %u diverted to NPP fake receive on conn jni handle %u", fn, serverJniHandle, connJniHandle); - delete (pSrv->mServerConn[ii]); - pSrv->mServerConn[ii] = NULL; - mRcvFakeNppJniHandle = connJniHandle; - return (true); - } - if (pSrv->mServerConn[ii]->mNfaConnHandle == NFA_HANDLE_INVALID) { delete (pSrv->mServerConn[ii]); @@ -694,18 +668,7 @@ void PeerToPeer::removeConn(tJNI_HANDLE jniHandle) } } - if (jniHandle == mRcvFakeNppJniHandle) - { - ALOGD ("%s: Reset mRcvFakeNppJniHandle: %u", fn, jniHandle); - mRcvFakeNppJniHandle = 0; - if (mNppFakeOutBuffer != NULL) - { - free (mNppFakeOutBuffer); - mNppFakeOutBuffer = NULL; - } - } - else - ALOGE ("%s: could not find handle: %u", fn, jniHandle); + ALOGE ("%s: could not find handle: %u", fn, jniHandle); } @@ -724,46 +687,6 @@ bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, const char* service { static const char fn [] = "PeerToPeer::connectConnOriented"; ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName); - - // If we are connecting to NPP and the other side supports SNEP, use SNEP - if ( (sNppServiceName.compare(serviceName)==0) && (mSnepRegHandle != NFA_HANDLE_INVALID) ) - { - P2pClient *pClient = NULL; - - if ((pClient = findClient (jniHandle)) == NULL) - { - ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); - return (false); - } - - if (mJniHandleSendingNppViaSnep != 0) - { - ALOGE ("%s: SNEP already active, SNEP JNI handle: %u new JNI handle: %u", fn, mJniHandleSendingNppViaSnep, jniHandle); - return (false); - } - - // Save JNI Handle and try to connect to SNEP - mJniHandleSendingNppViaSnep = jniHandle; - { - SyncEventGuard guard (pClient->mSnepEvent); - if (NFA_SnepConnect (mSnepRegHandle, const_cast("urn:nfc:sn:snep")) == NFA_STATUS_OK) - { - pClient->mSnepEvent.wait(); - - // If the connect attempt failed, connection handle is invalid - if (pClient->mSnepConnHandle != NFA_HANDLE_INVALID) - { - // return true, as if we were connected. - pClient->mClientConn.mRemoteMaxInfoUnit = 248; - pClient->mClientConn.mRemoteRecvWindow = 1; - return (true); - } - } - } - mJniHandleSendingNppViaSnep = 0; - } - - // If here, we did not establish a SNEP connection bool stat = createDataLinkConn (jniHandle, serviceName, 0); ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); return stat; @@ -1024,14 +947,8 @@ bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) return (false); } - ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X mJniHandleSendingNppViaSnep: %u", - fn, pConn->mJniHandle, pConn->mNfaConnHandle, mJniHandleSendingNppViaSnep); - - // Is this a SNEP fake-out - if (jniHandle == mJniHandleSendingNppViaSnep) - { - return (sendViaSnep(jniHandle, buffer, bufferLen)); - } + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X", + fn, pConn->mJniHandle, pConn->mNfaConnHandle); while (true) { @@ -1061,89 +978,6 @@ bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) /******************************************************************************* ** -** Function: sendViaSnep -** -** Description: Send out-bound data to the stack's SNEP protocol. -** jniHandle: Handle of connection. -** buffer: Buffer of data. -** dataLen: Length of data. -** -** Returns: True if ok. -** -*******************************************************************************/ -bool PeerToPeer::sendViaSnep (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 dataLen) -{ - static const char fn [] = "PeerToPeer::sendViaSnep"; - tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - P2pClient *pClient = NULL; - - if ((pClient = findClient (jniHandle)) == NULL) - { - ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); - mJniHandleSendingNppViaSnep = 0; - return (false); - } - - ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u mSnepNdefMsgLen: %lu mSnepNdefBufLen: %lu dataLen: %d", - fn, jniHandle, pClient->mSnepNdefMsgLen, pClient->mSnepNdefBufLen, dataLen); - - if (pClient->mSnepNdefMsgLen == 0) - { - pClient->mSnepNdefMsgLen = (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | buffer[9]; - if ((pClient->mSnepNdefBuf = (UINT8 *)malloc (pClient->mSnepNdefMsgLen + 1000)) == NULL) - { - ALOGE ("%s: can't malloc len: %lu", fn, pClient->mSnepNdefMsgLen); - mJniHandleSendingNppViaSnep = 0; - return (false); - } - buffer += 10; - dataLen -= 10; - } - - if ((pClient->mSnepNdefBufLen + dataLen) > pClient->mSnepNdefMsgLen) - { - ALOGE ("%s: len error mSnepNdefBufLen: %lu dataLen: %u mSnepNdefMsgLen: %lu", fn, - pClient->mSnepNdefBufLen, dataLen, pClient->mSnepNdefMsgLen); - mJniHandleSendingNppViaSnep = 0; - free (pClient->mSnepNdefBuf); - pClient->mSnepNdefBuf = NULL; - return (false); - } - - // Save the data in the buffer - memcpy (pClient->mSnepNdefBuf + pClient->mSnepNdefBufLen, buffer, dataLen); - - pClient->mSnepNdefBufLen += dataLen; - - // If we got all the data, send it via SNEP - if (pClient->mSnepNdefBufLen == pClient->mSnepNdefMsgLen) - { - ALOGD ("%s GKI_poolcount(2): %u GKI_poolfreecount(2): %u", fn, GKI_poolcount(2), GKI_poolfreecount(2)); - - SyncEventGuard guard (pClient->mSnepEvent); - nfaStat = NFA_SnepPut (pClient->mSnepConnHandle, pClient->mSnepNdefBufLen, pClient->mSnepNdefBuf); - - if (nfaStat != NFA_STATUS_OK) - { - ALOGE ("%s: NFA_SnepPut failed, code: 0x%04x", fn, nfaStat); - mJniHandleSendingNppViaSnep = 0; - free (pClient->mSnepNdefBuf); - pClient->mSnepNdefBuf = NULL; - return (false); - } - pClient->mSnepEvent.wait (); - - free (pClient->mSnepNdefBuf); - pClient->mSnepNdefBuf = NULL; - mJniHandleSendingNppViaSnep = 0; - return (pClient->mIsSnepSentOk); - } - return (true); -} - - -/******************************************************************************* -** ** Function: receive ** ** Description: Receive data from peer. @@ -1165,9 +999,6 @@ bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen BOOLEAN isMoreData = TRUE; bool retVal = false; - if (jniHandle == mRcvFakeNppJniHandle) - return (feedNppFromSnep(buffer, bufferLen, actualLen)); - if ((pConn = findConnection (jniHandle)) == NULL) { ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); @@ -1200,44 +1031,6 @@ bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen /******************************************************************************* ** -** Function: feedNppFromSnep -** -** Description: Send incomming data to the NFC service's NDEF Push Protocol. -** buffer: Buffer of data to send. -** bufferLen: Length of data in buffer. -** actualLen: Actual length sent. -** -** Returns: True if ok. -** -*******************************************************************************/ -bool PeerToPeer::feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) -{ - static const char fn [] = "PeerToPeer::feedNppFromSnep"; - - ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: mNppTotalLen: %lu mNppReadSoFar: %lu bufferLen: %u", - fn, mNppTotalLen, mNppReadSoFar, bufferLen); - - if (bufferLen > (mNppTotalLen - mNppReadSoFar)) - bufferLen = mNppTotalLen - mNppReadSoFar; - - memcpy (buffer, mNppFakeOutBuffer + mNppReadSoFar, bufferLen); - - mNppReadSoFar += bufferLen; - actualLen = bufferLen; - - if (mNppReadSoFar == mNppTotalLen) - { - ALOGD ("%s: entire message consumed", fn); - free (mNppFakeOutBuffer); - mNppFakeOutBuffer = NULL; - mRcvFakeNppJniHandle = 0; - } - return (true); -} - - -/******************************************************************************* -** ** Function: disconnectConnOriented ** ** Description: Disconnect a connection-oriented connection with peer. @@ -1483,15 +1276,6 @@ void PeerToPeer::handleNfcOnOff (bool isOn) } } //loop - mJniHandleSendingNppViaSnep = 0; - mRcvFakeNppJniHandle = 0; - mSnepRegHandle = NFA_HANDLE_INVALID; - - if (mNppFakeOutBuffer != NULL) - { - free (mNppFakeOutBuffer); - mNppFakeOutBuffer = NULL; - } } ALOGD ("%s: exit", fn); } @@ -1801,188 +1585,6 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev /******************************************************************************* ** -** Function: snepClientCallback -** -** Description: Receive SNEP-related events from the stack. -** snepEvent: Event code. -** eventData: Event data. -** -** Returns: None -** -*******************************************************************************/ -void PeerToPeer::snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData) -{ - static const char fn [] = "PeerToPeer::snepClientCallback"; - P2pClient *pClient; - - switch (snepEvent) - { - case NFA_SNEP_REG_EVT: - { - ALOGD ("%s NFA_SNEP_REG_EVT Status: %u Handle: 0x%X", fn, eventData->reg.status, eventData->reg.reg_handle); - SyncEventGuard guard (sP2p.mSnepRegisterEvent); - if (eventData->reg.status == NFA_STATUS_OK) - sP2p.mSnepRegHandle = eventData->reg.reg_handle; - sP2p.mSnepRegisterEvent.notifyOne (); - break; - } - - case NFA_SNEP_ACTIVATED_EVT: - ALOGD ("%s NFA_SNEP_ACTIVATED_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - break; - - case NFA_SNEP_DEACTIVATED_EVT: - ALOGD ("%s NFA_SNEP_ACTIVATED_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - break; - - case NFA_SNEP_CONNECTED_EVT: - if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) - { - ALOGE ("%s: NFA_SNEP_CONNECTED_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - } - else - { - ALOGD ("%s NFA_SNEP_CONNECTED_EVT mJniHandleSendingNppViaSnep: %u ConnHandle: 0x%04x", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->connect.conn_handle); - - SyncEventGuard guard (pClient->mSnepEvent); - pClient->mSnepConnHandle = eventData->connect.conn_handle; - pClient->mSnepEvent.notifyOne(); - } - break; - - case NFA_SNEP_PUT_RESP_EVT: - if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) - { - ALOGE ("%s: NFA_SNEP_PUT_RESP_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - } - else - { - ALOGD ("%s NFA_SNEP_PUT_RESP_EVT mJniHandleSendingNppViaSnep: %u Result: 0x%X", fn, sP2p.mJniHandleSendingNppViaSnep, eventData->put_resp.resp_code); - - pClient->mIsSnepSentOk = (eventData->put_resp.resp_code == NFA_SNEP_RESP_CODE_SUCCESS); - - NFA_SnepDisconnect (eventData->put_resp.conn_handle, FALSE); - - SyncEventGuard guard (pClient->mSnepEvent); - pClient->mSnepEvent.notifyOne(); - } - break; - - case NFA_SNEP_DISC_EVT: - if ((pClient = sP2p.findClient (sP2p.mJniHandleSendingNppViaSnep)) == NULL) - { - ALOGE ("%s: NFA_SNEP_DISC_EVT - can't find SNEP client, mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - } - else - { - ALOGD ("%s NFA_SNEP_DISC_EVT mJniHandleSendingNppViaSnep: %u", fn, sP2p.mJniHandleSendingNppViaSnep); - SyncEventGuard guard (pClient->mSnepEvent); - pClient->mSnepConnHandle = NFA_HANDLE_INVALID; - pClient->mSnepEvent.notifyOne(); - } - break; - - case NFA_SNEP_DEFAULT_SERVER_STARTED_EVT: - { - ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STARTED_EVT", fn); - SyncEventGuard guard (sP2p.mSnepDefaultServerStartStopEvent); - sP2p.mSnepDefaultServerStartStopEvent.notifyOne(); //unblock NFA_SnepStartDefaultServer() - break; - } - - case NFA_SNEP_DEFAULT_SERVER_STOPPED_EVT: - { - ALOGE ("%s: NFA_SNEP_DEFAULT_SERVER_STOPPED_EVT", fn); - SyncEventGuard guard (sP2p.mSnepDefaultServerStartStopEvent); - sP2p.mSnepDefaultServerStartStopEvent.notifyOne(); //unblock NFA_SnepStopDefaultServer() - break; - } - break; - - default: - ALOGE ("%s UNKNOWN EVENT: 0x%04x mJniHandleSendingNppViaSnep: %u", fn, snepEvent, sP2p.mJniHandleSendingNppViaSnep); - break; - } -} - - -/******************************************************************************* -** -** Function: ndefTypeCallback -** -** Description: Receive NDEF-related events from the stack. -** ndefEvent: Event code. -** eventData: Event data. -** -** Returns: None -** -*******************************************************************************/ -void PeerToPeer::ndefTypeCallback (tNFA_NDEF_EVT ndefEvent, tNFA_NDEF_EVT_DATA *eventData) -{ - static const char fn [] = "PeerToPeer::ndefTypeCallback"; - P2pServer *pSvr = NULL; - - if (ndefEvent == NFA_NDEF_REGISTER_EVT) - { - tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg; - ALOGD ("%s NFA_NDEF_REGISTER_EVT Status: %u; h=0x%X", fn, ndef_reg.status, ndef_reg.ndef_type_handle); - sP2p.mNdefTypeHandlerHandle = ndef_reg.ndef_type_handle; - } - else if (ndefEvent == NFA_NDEF_DATA_EVT) - { - ALOGD ("%s NFA_NDEF_DATA_EVT Len: %lu", fn, eventData->ndef_data.len); - - if (sP2p.mRcvFakeNppJniHandle != 0) - { - ALOGE ("%s Got NDEF Data while busy, mRcvFakeNppJniHandle: %u", fn, sP2p.mRcvFakeNppJniHandle); - return; - } - - if ((pSvr = sP2p.findServer ("com.android.npp")) == NULL) - { - ALOGE ("%s Got NDEF Data but no NPP server listening", fn); - return; - } - - if ((sP2p.mNppFakeOutBuffer = (UINT8 *)malloc(eventData->ndef_data.len + 10)) == NULL) - { - ALOGE ("%s failed to malloc: %lu bytes", fn, eventData->ndef_data.len + 10); - return; - } - - sP2p.mNppFakeOutBuffer[0] = 0x01; - sP2p.mNppFakeOutBuffer[1] = 0x00; - sP2p.mNppFakeOutBuffer[2] = 0x00; - sP2p.mNppFakeOutBuffer[3] = 0x00; - sP2p.mNppFakeOutBuffer[4] = 0x01; - sP2p.mNppFakeOutBuffer[5] = 0x01; - sP2p.mNppFakeOutBuffer[6] = (UINT8)(eventData->ndef_data.len >> 24); - sP2p.mNppFakeOutBuffer[7] = (UINT8)(eventData->ndef_data.len >> 16); - sP2p.mNppFakeOutBuffer[8] = (UINT8)(eventData->ndef_data.len >> 8); - sP2p.mNppFakeOutBuffer[9] = (UINT8)(eventData->ndef_data.len); - - memcpy (&sP2p.mNppFakeOutBuffer[10], eventData->ndef_data.p_data, eventData->ndef_data.len); - - ALOGD ("%s NFA_NDEF_DATA_EVT Faking NPP on Server Handle: %u", fn, pSvr->mJniHandle); - - sP2p.mRcvFakeNppJniHandle = pSvr->mJniHandle; - sP2p.mNppTotalLen = eventData->ndef_data.len + 10; - sP2p.mNppReadSoFar = 0; - { - SyncEventGuard guard (pSvr->mConnRequestEvent); - pSvr->mConnRequestEvent.notifyOne(); - } - } - else - { - ALOGE ("%s UNKNOWN EVENT: 0x%X", fn, ndefEvent); - } - -} - - -/******************************************************************************* -** ** Function: connectionEventHandler ** ** Description: Receive events from the stack. @@ -2087,12 +1689,7 @@ NfaConn *P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) *******************************************************************************/ P2pClient::P2pClient () : mNfaP2pClientHandle (NFA_HANDLE_INVALID), - mIsConnecting (false), - mSnepConnHandle (NFA_HANDLE_INVALID), - mSnepNdefMsgLen (0), - mSnepNdefBufLen (0), - mSnepNdefBuf (NULL), - mIsSnepSentOk (false) + mIsConnecting (false) { } @@ -2108,8 +1705,6 @@ P2pClient::P2pClient () *******************************************************************************/ P2pClient::~P2pClient () { - if (mSnepNdefBuf) - free (mSnepNdefBuf); } diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index 2921492..040ca78 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -340,13 +340,6 @@ private: UINT16 mRemoteWKS; // Peer's well known services bool mIsP2pListening; // If P2P listening is enabled or not tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask - tJNI_HANDLE mJniHandleSendingNppViaSnep; - tNFA_HANDLE mSnepRegHandle; - tJNI_HANDLE mRcvFakeNppJniHandle; - UINT8 *mNppFakeOutBuffer; - UINT32 mNppTotalLen; - UINT32 mNppReadSoFar; - tNFA_HANDLE mNdefTypeHandlerHandle; tJNI_HANDLE mNextJniHandle; P2pServer *mServers [sMax]; @@ -557,36 +550,6 @@ private: ** *******************************************************************************/ NfaConn *findConnection (tJNI_HANDLE jniHandle); - - - /******************************************************************************* - ** - ** Function: sendViaSnep - ** - ** Description: Send out-bound data to the stack's SNEP protocol. - ** jniHandle: Handle of connection. - ** buffer: Buffer of data. - ** dataLen: Length of data. - ** - ** Returns: True if ok. - ** - *******************************************************************************/ - bool sendViaSnep (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen); - - - /******************************************************************************* - ** - ** Function: feedNppFromSnep - ** - ** Description: Send incomming data to the NFC service's NDEF Push Protocol. - ** buffer: Buffer of data to send. - ** bufferLen: Length of data in buffer. - ** actualLen: Actual length sent. - ** - ** Returns: True if ok. - ** - *******************************************************************************/ - bool feedNppFromSnep (UINT8* buffer, UINT16 bufferLen, UINT16& actualLen); }; @@ -679,11 +642,6 @@ class P2pClient public: tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client bool mIsConnecting; // Set true while connecting - tNFA_HANDLE mSnepConnHandle; - UINT32 mSnepNdefMsgLen; // SNEP total NDEF message length - UINT32 mSnepNdefBufLen; // SNEP NDEF buffer length - UINT8 *mSnepNdefBuf; // SNEP NDEF Message - bool mIsSnepSentOk; // SNEP transmission status NfaConn mClientConn; SyncEvent mRegisteringEvent; // For client registration SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap() -- cgit v1.1 From f9f309b683526876dae196a706ac520f05eb22c0 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 6 Sep 2012 16:45:16 +0200 Subject: Do not dispatch empty NDEF tags as NDEF_DISCOVERED. To avoid encouraging sloppy filtering. This was actually already the behavior pre-JB. Change-Id: I556f250db086b70345123a151378728080b4779c --- src/com/android/nfc/NfcDispatcher.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/nfc/NfcDispatcher.java b/src/com/android/nfc/NfcDispatcher.java index b3ab97c..f628dea 100644 --- a/src/com/android/nfc/NfcDispatcher.java +++ b/src/com/android/nfc/NfcDispatcher.java @@ -305,7 +305,10 @@ public class NfcDispatcher { if (message == null) { return false; } - dispatch.setNdefIntent(); + Intent intent = dispatch.setNdefIntent(); + + // Bail out if the intent does not contain filterable NDEF data + if (intent == null) return false; // Try to start AAR activity with matching filter List aarPackages = extractAarPackages(message); -- cgit v1.1 From 2bc17929536528973571087813cb9746ea4947a6 Mon Sep 17 00:00:00 2001 From: Paul Chaisson Date: Thu, 6 Sep 2012 23:54:55 -0400 Subject: Use NFA_DM_DISC_DURATION_POLL from config file. Use the poll duration ("NFA_DM_DISC_DURATION_POLL") from the conf file if one is configured. Change-Id: If17d402cbe8505b096a168640f99b88f7e3b6e48 --- nci/jni/NativeNfcManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 14e9cb9..ca1bb06 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -741,6 +741,10 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) NFA_SetMultiTechRsp(TRUE); + // if this value exists, set polling interval. + if (GetNumValue(NAME_NFA_DM_DISC_DURATION_POLL, &num, sizeof(num))) + NFA_SetRfDiscoveryDuration(num); + // Do custom NFCA startup configuration. doStartupConfig(); goto TheEnd; -- cgit v1.1 From cf72e2c30b6f0006068a3fa2ba02dba4917e7fb6 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Fri, 31 Aug 2012 09:20:55 -0400 Subject: Fix NFC low-power modes. At the end of nfcManager_doInitialize(), enter low-power mode. This logic is used after boot and before the user unlocks the screen. If the user does not unlock the screen, the phone stays in low-power mode. Additionally, only power off the chip if discovery is disabled AND the SE is not selected. Change-Id: I2bd2effce34b5dc586ad484c1da2ae86da49f0c1 --- nci/jni/NativeNfcManager.cpp | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index ca1bb06..b97a20f 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -504,8 +504,6 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) return JNI_FALSE; } - PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); - ALOGD ("%s: exit", __FUNCTION__); return JNI_TRUE; } @@ -660,6 +658,8 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) goto TheEnd; } + PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER); + { unsigned long num = 0; tBRCM_DEV_INIT_CONFIG devInitConfig; @@ -760,6 +760,7 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) } TheEnd: + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); ALOGD ("%s: exit", __FUNCTION__); return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE; } @@ -852,8 +853,6 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) if (sDiscoveryEnabled == false) { ALOGD ("%s: already disabled", __FUNCTION__); - if (! sIsSecElemSelected) - PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); goto TheEnd; } @@ -874,7 +873,9 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) } PeerToPeer::getInstance().enableP2pListening (false); - PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + + if (!sIsSecElemSelected) + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); TheEnd: ALOGD ("%s: exit", __FUNCTION__); @@ -1231,7 +1232,6 @@ static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { ALOGD ("%s: enter", __FUNCTION__); bool stat = false; - bool isPowerLevelChanged = false; if (! sIsSecElemSelected) { @@ -1257,7 +1257,7 @@ static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) TheEnd: //if power level was changed at the top of this method, //then restore to low power - if (isPowerLevelChanged || (!PowerSwitch::getInstance().isScreenOn() && (sDiscoveryEnabled == false)) ) + if (!sDiscoveryEnabled) PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); ALOGD ("%s: exit", __FUNCTION__); } @@ -1635,6 +1635,7 @@ void doStartupConfig() { unsigned long num = 0; struct nfc_jni_native_data *nat = getNative(0, 0); + tNFA_STATUS stat = NFA_STATUS_FAILED; // Enable the "RC workaround" to allow our stack/firmware to work with a retail // Nexus S that causes IOP issues. Only enable if value exists and set to 1. @@ -1647,14 +1648,20 @@ void doStartupConfig() #endif ALOGD ("%s: Configure RC work-around", __FUNCTION__); - NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]); + SyncEventGuard guard (sNfaSetConfigEvent); + stat = NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]); + if (stat == NFA_STATUS_OK) + sNfaSetConfigEvent.wait (); } // If polling for Active mode, set the ordering so that we choose Active over Passive mode first. if (nat && (nat->tech_mask & (NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE))) { UINT8 act_mode_order_param[] = { 0x01 }; - NFA_SetConfig(NCI_PARAM_ID_ACT_ORDER, sizeof(act_mode_order_param), &act_mode_order_param[0]); + SyncEventGuard guard (sNfaSetConfigEvent); + stat = NFA_SetConfig(NCI_PARAM_ID_ACT_ORDER, sizeof(act_mode_order_param), &act_mode_order_param[0]); + if (stat == NFA_STATUS_OK) + sNfaSetConfigEvent.wait (); } // Set configuration to allow UICC to Power off if there is no traffic. @@ -1674,7 +1681,10 @@ void doStartupConfig() UINT8 * p = &swpcfg_param[12]; UINT32_TO_STREAM(p, num) - NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]); + SyncEventGuard guard (sNfaSetConfigEvent); + stat = NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]); + if (stat == NFA_STATUS_OK) + sNfaSetConfigEvent.wait (); } // Set antenna tuning configuration if configured. @@ -1683,7 +1693,10 @@ void doStartupConfig() if (GetStrValue(NAME_PREINIT_DSP_CFG, (char*)&preinit_dsp_param[0], sizeof(preinit_dsp_param))) { - NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_param[0]); + SyncEventGuard guard (sNfaSetConfigEvent); + stat = NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_param[0]); + if (stat == NFA_STATUS_OK) + sNfaSetConfigEvent.wait (); } } -- cgit v1.1 From 9fecbe852683f1bae8dc789c089028acc1ddae20 Mon Sep 17 00:00:00 2001 From: Doris Liu Date: Fri, 7 Sep 2012 14:18:30 -0700 Subject: Add FLAG_ACTIVITY_NEW_TASK to viewIntent The previous CL that set FLAG_ACTIVITY_NEW_TASK flag in pendingIntent did not fix the bug. The flag needs to be set in the view intent. Bug: 6925612 Change-Id: Ibe5892c575fdf904c800c726122c59be6af02685 --- src/com/android/nfc/handover/HandoverManager.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index 8983389..b4c2025 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -390,8 +390,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, notBuilder.setContentText(mContext.getString(R.string.beam_touch_to_view)); Intent viewIntent = buildViewIntent(); - PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, - Intent.FLAG_ACTIVITY_NEW_TASK); + PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, 0); notBuilder.setContentIntent(contentIntent); @@ -538,7 +537,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, Uri uri = mediaUri != null ? mediaUri : Uri.parse(ContentResolver.SCHEME_FILE + "://" + filePath); viewIntent.setDataAndTypeAndNormalize(uri, mimeTypes.get(filePath)); - + viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return viewIntent; } -- cgit v1.1 From 0056bce9a6b688959e94b70cc80fb8ae331d9af9 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Mon, 10 Sep 2012 11:07:13 -0400 Subject: Use correct app name for NFA_HciDeregister() The "app name" parameters must match in HciDregister() and HciRegister() Change-Id: I43010268bb4c0ee7cdc7c1440346a6dedc230a58 --- nci/jni/SecureElement.cpp | 5 +++-- nci/jni/SecureElement.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index e4d9400..57c33bb 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -36,6 +36,7 @@ bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if SecureElement SecureElement::sSecElem; +const char* SecureElement::APP_NAME = "nfc_jni"; /******************************************************************************* @@ -184,7 +185,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) SyncEventGuard guard (mHciRegisterEvent); - nfaStat = NFA_HciRegister (const_cast("nfc_jni"), nfaHciCallback, TRUE); + nfaStat = NFA_HciRegister (const_cast(APP_NAME), nfaHciCallback, TRUE); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat); @@ -223,7 +224,7 @@ void SecureElement::finalize () NFA_EeDeregister (nfaEeCallback); if (mNfaHciHandle != NFA_HANDLE_INVALID) - NFA_HciDeregister (const_cast("brcm_jni")); + NFA_HciDeregister (const_cast(APP_NAME)); mNfaHciHandle = NFA_HANDLE_INVALID; mNativeData = NULL; diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index 65e779e..bfa54cc 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -347,6 +347,7 @@ private: static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0 static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1 static SecureElement sSecElem; + static const char* APP_NAME; UINT8 mDestinationGate; //destination gate of the UICC tNFA_HANDLE mNfaHciHandle; //NFA handle to NFA's HCI component -- cgit v1.1 From 643bf71c665fd08b5a5cd367a8baa2da52116c64 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Wed, 5 Sep 2012 10:14:19 -0400 Subject: User proper error code during tag reading When reading a tag and it does not respond to a command, use taglost=1. It causes a TagLostException in the app. Bug: 7047415 Change-Id: I766849991441b82e5ad03d3031bc735fa5f9c27a --- nci/jni/NativeNfcTag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index b4b517b..d4281ce 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -857,7 +857,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da { ALOGE ("%s: wait response timeout", __FUNCTION__); if (targetLost) - *targetLost = 2; //causes NFC service to throw IOException + *targetLost = 1; //causes NFC service to throw TagLostException break; } -- cgit v1.1 From c6cf8e45c27d8a43d09b997cc223e8068d140edd Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Thu, 13 Sep 2012 17:43:41 -0400 Subject: Integrate NFC Hardware Abstraction Layer. Bug: 7123942 Change-Id: I4fa153b80e1af2b00b326370e102f714cde4334b --- nci/jni/Android.mk | 2 ++ nci/jni/NativeNfcManager.cpp | 65 +++-------------------------------------- nci/jni/NativeSecureElement.cpp | 1 - nci/jni/PowerSwitch.cpp | 12 -------- nci/jni/SecureElement.cpp | 2 -- 5 files changed, 6 insertions(+), 76 deletions(-) diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk index 335e5f1..414f827 100644 --- a/nci/jni/Android.mk +++ b/nci/jni/Android.mk @@ -30,6 +30,8 @@ LOCAL_C_INCLUDES += \ $(NFC)/include \ $(NFC)/brcm \ $(NFC)/int \ + $(VOB_COMPONENTS)/hal/include \ + $(VOB_COMPONENTS)/hal/int \ $(VOB_COMPONENTS)/include \ $(VOB_COMPONENTS)/gki/ulinux \ $(VOB_COMPONENTS)/gki/common diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index b97a20f..fcab063 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -32,17 +32,16 @@ extern "C" { #include "nfa_api.h" #include "nfa_p2p_api.h" - #include "nfa_dta_api.h" #include "rw_api.h" #include "nfa_ee_api.h" - #include "nfa_brcm_api.h" + #include "nfc_brcm_defs.h" #include "nfa_cho_api.h" + #include "ce_api.h" } extern UINT8 *p_nfa_dm_lptd_cfg; extern UINT8 *p_nfa_dm_start_up_cfg; extern const UINT8 nfca_version_string []; -extern "C" void downloadFirmwarePatchFile (UINT32 brcm_hw_id); namespace android { extern bool gIsTagDeactivating; @@ -106,7 +105,6 @@ static SyncEvent sNfaEnableEvent; //event for NFA_Enable() static SyncEvent sNfaDisableEvent; //event for NFA_Disable() static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling() static SyncEvent sNfaSetConfigEvent; // event for Set_Config.... -static SyncEvent sNfaBuildInfoEvent; static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; @@ -133,7 +131,6 @@ static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); static bool isPeerToPeer (tNFA_ACTIVATED& activated); static void startRfDiscovery (bool isStart); -static void nfaBrcmInitCallback (UINT32 brcm_hw_id, UINT8 nvm_type); ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// @@ -616,19 +613,6 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData); break; - case NFA_DM_FIRMWARE_BUILD_INFO_EVT: - { - tNFA_BRCM_FW_BUILD_INFO* bldInfo = - (tNFA_BRCM_FW_BUILD_INFO*) eventData->p_vs_evt_data; - if (bldInfo != NULL) { - ALOGE("BCM2079x NFC FW version %d.%d", bldInfo->patch.major_ver, - bldInfo->patch.minor_ver); - } - SyncEventGuard versionGuard (sNfaBuildInfoEvent); - sNfaBuildInfoEvent.notifyOne(); - } - break; - default: ALOGD ("%s: unhandled event", __FUNCTION__); break; @@ -662,24 +646,15 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) { unsigned long num = 0; - tBRCM_DEV_INIT_CONFIG devInitConfig; - memset (&devInitConfig, 0, sizeof(devInitConfig)); NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Initialize(); //start GKI, NCI task, NFC task { SyncEventGuard guard (sNfaEnableEvent); - NFA_Init(); - - // Initialize the Crystal Frequency if configured. - if (GetNumValue((char*)NAME_XTAL_FREQUENCY, &devInitConfig.xtal_freq, sizeof(devInitConfig.xtal_freq))) - { - ALOGD("%s: setting XTAL Frequency=%d", __FUNCTION__, devInitConfig.xtal_freq); - devInitConfig.flags |= BRCM_DEV_INIT_FLAGS_SET_XTAL_FREQ; - } + tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs (); - NFA_BrcmInit (&devInitConfig, nfaBrcmInitCallback); + NFA_Init (halFuncEntries); stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback); if (stat == NFA_STATUS_OK) @@ -688,7 +663,6 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) CE_SetTraceLevel (num); LLCP_SetTraceLevel (num); NFC_SetTraceLevel (num); - NCI_SetTraceLevel (num); RW_SetTraceLevel (num); NFA_SetTraceLevel (num); NFA_ChoSetTraceLevel (num); @@ -703,14 +677,6 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) //sIsNfaEnabled indicates whether stack started successfully if (sIsNfaEnabled) { - { - SyncEventGuard versionGuard (sNfaBuildInfoEvent); - stat = NFA_BrcmGetFirmwareBuildInfo(); - if (stat == NFA_STATUS_OK) { - sNfaBuildInfoEvent.wait(); - } - } - SecureElement::getInstance().initialize (getNative(e, o)); nativeNfcTag_registerNdefTypeHandler (); NfcTag::getInstance().initialize (getNative(e, o)); @@ -736,11 +702,6 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) if (sOriginalLptdCfg != NULL) p_nfa_dm_lptd_cfg = sOriginalLptdCfg; - - // if this value is not set or set and non-zero, enable multi-technology responses. - if (!GetNumValue(NAME_NFA_DM_MULTI_TECH_RESP, &num, sizeof(num)) || (num != 0)) - NFA_SetMultiTechRsp(TRUE); - // if this value exists, set polling interval. if (GetNumValue(NAME_NFA_DM_DISC_DURATION_POLL, &num, sizeof(num))) NFA_SetRfDiscoveryDuration(num); @@ -1716,23 +1677,5 @@ bool nfcManager_isNfcActive() } -/******************************************************************************* -** -** Function: nfaBrcmInitCallback -** -** Description: Callback function for application to start device initialization. -** When platform-specific initialization is completed, -** NCI_BrcmDevInitDone() must be called to proceed with stack start up. -** -** Returns: None. -** -*******************************************************************************/ -void nfaBrcmInitCallback (UINT32 brcm_hw_id, UINT8 nvm_type) -{ - ALOGD ("%s: enter; brcm_hw_id=0x%lX; nvm_type=0x%X", __FUNCTION__, brcm_hw_id, nvm_type); - downloadFirmwarePatchFile (brcm_hw_id); -} - - } /* namespace android */ diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp index 7054b26..9fa27e3 100755 --- a/nci/jni/NativeSecureElement.cpp +++ b/nci/jni/NativeSecureElement.cpp @@ -17,7 +17,6 @@ #include "OverrideLog.h" #include "SecureElement.h" #include "JavaClassConstants.h" -#include "nfa_brcm_api.h" namespace android diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp index ba1a96b..11d1abe 100755 --- a/nci/jni/PowerSwitch.cpp +++ b/nci/jni/PowerSwitch.cpp @@ -13,7 +13,6 @@ #include "NfcJniUtil.h" #include "config.h" #include "SecureElement.h" -#include "userial.h" namespace android @@ -226,17 +225,6 @@ bool PowerSwitch::setPowerOffSleepState (bool sleep) { mPowerStateEvent.wait (); mCurrLevel = LOW_POWER; - ALOGD ("%s: wait for userial close", fn); - int count = 0; - while (USERIAL_IsClosed() == FALSE) - { - //must wait for userial to close completely; - //otherwise there is a race condition when the next operation - //wants to go to full-power again; - count++; - usleep (5000); //5 milliseconds = 5 000 microseconds - } - ALOGD ("%s: userial close ok; count=%d", fn, count); } else { diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 57c33bb..5008998 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -16,8 +16,6 @@ #include "config.h" #include "PowerSwitch.h" #include "HostAidRouter.h" -#include "nfa_vs_brcm_api.h" -#include "nfa_brcm_api.h" #include "JavaClassConstants.h" -- cgit v1.1 From 7be608bcc4495aafcb700aa61072050fdc96f3e8 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 17 Sep 2012 17:28:40 -0700 Subject: Fix locking in PeerToPeer. The PeerToPeer class had some serious multi-threading issues: - mServers / mClients simultaneously being accessed by different threads - P2pServer / P2pClient objects being deleted while still being used by other threads - Race conditions where we could go to sleep on a condition variable without ever waking up. This fixes most of the issues by: - Properly locking all access to mServers / mClients - Using Android's sp mechanism to do ref counting on P2pServer/P2pClient/NfaConn TODO: - Fix races around the condition variables - those are very hard to hit, but we need them fixed anyway. Bug: 7089048 Change-Id: I08564c65cc40734086e517d6107e31f86c3b6adc --- nci/jni/Android.mk | 1 + nci/jni/Mutex.h | 11 ++ nci/jni/PeerToPeer.cpp | 520 +++++++++++++++++++++++++++++-------------------- nci/jni/PeerToPeer.h | 185 +++++++++++++----- 4 files changed, 462 insertions(+), 255 deletions(-) diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk index 414f827..39832fd 100644 --- a/nci/jni/Android.mk +++ b/nci/jni/Android.mk @@ -25,6 +25,7 @@ LOCAL_C_INCLUDES += \ external/stlport/stlport \ external/libxml2/include \ external/icu4c/common \ + frameworks/native/include \ $(NFA)/include \ $(NFA)/brcm \ $(NFC)/include \ diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h index bd762c2..1b500ee 100644 --- a/nci/jni/Mutex.h +++ b/nci/jni/Mutex.h @@ -87,7 +87,18 @@ public: *******************************************************************************/ pthread_mutex_t* nativeHandle (); + class Autolock { + public: + inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); } + inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); } + inline ~Autolock() { mLock.unlock(); } + private: + Mutex& mLock; + }; + + private: pthread_mutex_t mMutex; }; +typedef Mutex::Autolock AutoMutex; diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index bf18df5..78132b8 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -15,6 +15,8 @@ #include "config.h" #include "JavaClassConstants.h" +using namespace android; + namespace android { extern void nativeNfcTag_registerNdefTypeHandler (); @@ -23,7 +25,7 @@ namespace android PeerToPeer PeerToPeer::sP2p; -const std::string PeerToPeer::sSnepServiceName ("urn:nfc:sn:snep"); +const std::string P2pServer::sSnepServiceName ("urn:nfc:sn:snep"); /******************************************************************************* @@ -100,15 +102,16 @@ void PeerToPeer::initialize () /******************************************************************************* ** -** Function: findServer +** Function: findServerLocked ** ** Description: Find a PeerToPeer object by connection handle. +** Assumes mMutex is already held ** nfaP2pServerHandle: Connectin handle. ** ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pServer *PeerToPeer::findServer (tNFA_HANDLE nfaP2pServerHandle) +sp PeerToPeer::findServerLocked (tNFA_HANDLE nfaP2pServerHandle) { for (int i = 0; i < sMax; i++) { @@ -126,15 +129,16 @@ P2pServer *PeerToPeer::findServer (tNFA_HANDLE nfaP2pServerHandle) /******************************************************************************* ** -** Function: findServer +** Function: findServerLocked ** ** Description: Find a PeerToPeer object by connection handle. +** Assumes mMutex is already held ** serviceName: service name. ** ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pServer *PeerToPeer::findServer (tJNI_HANDLE jniHandle) +sp PeerToPeer::findServerLocked (tJNI_HANDLE jniHandle) { for (int i = 0; i < sMax; i++) { @@ -152,15 +156,16 @@ P2pServer *PeerToPeer::findServer (tJNI_HANDLE jniHandle) /******************************************************************************* ** -** Function: findServer +** Function: findServerLocked ** ** Description: Find a PeerToPeer object by service name +** Assumes mMutex is already heldf ** serviceName: service name. ** ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pServer *PeerToPeer::findServer (const char *serviceName) +sp PeerToPeer::findServerLocked (const char *serviceName) { for (int i = 0; i < sMax; i++) { @@ -189,16 +194,18 @@ bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName) static const char fn [] = "PeerToPeer::registerServer"; ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle); tNFA_STATUS stat = NFA_STATUS_OK; - P2pServer *pSrv = NULL; + sp pSrv = NULL; UINT8 serverSap = NFA_P2P_ANY_SAP; + mMutex.lock(); // Check if already registered - if ((pSrv = findServer(serviceName)) != NULL) + if ((pSrv = findServerLocked(serviceName)) != NULL) { ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle); // Update JNI handle pSrv->mJniHandle = jniHandle; + mMutex.unlock(); return (true); } @@ -206,14 +213,13 @@ bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName) { if (mServers[ii] == NULL) { - pSrv = mServers[ii] = new P2pServer; - pSrv->mServiceName.assign (serviceName); - pSrv->mJniHandle = jniHandle; + pSrv = mServers[ii] = new P2pServer(jniHandle, serviceName); ALOGD ("%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName); break; } } + mMutex.unlock(); if (pSrv == NULL) { @@ -221,58 +227,14 @@ bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName) return (false); } - /********************** - default values for all LLCP parameters: - - Local Link MIU (LLCP_MIU) - - Option parameter (LLCP_OPT_VALUE) - - Response Waiting Time Index (LLCP_WAITING_TIME) - - Local Link Timeout (LLCP_LTO_VALUE) - - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT) - - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT) - - Delay SYMM response (LLCP_DELAY_RESP_TIME) - - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) - - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) - ************************/ - stat = NFA_P2pSetLLCPConfig (LLCP_MIU, - LLCP_OPT_VALUE, - LLCP_WAITING_TIME, - LLCP_LTO_VALUE, - 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator - 0, //use 0 for infinite timeout for symmetry procedure when acting as target - LLCP_DELAY_RESP_TIME, - LLCP_DATA_LINK_CONNECTION_TOUT, - LLCP_DELAY_TIME_TO_SEND_FIRST_PDU); - if (stat != NFA_STATUS_OK) - ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat); - - if (sSnepServiceName.compare(serviceName) == 0) - serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 - - { - SyncEventGuard guard (pSrv->mRegServerEvent); - stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(serviceName), nfaServerCallback); - if (stat != NFA_STATUS_OK) - { - ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); - removeServer (jniHandle); - return (false); - } - ALOGD ("%s: wait for listen-completion event", fn); - // Wait for NFA_P2P_REG_SERVER_EVT - pSrv->mRegServerEvent.wait (); - } - - if (pSrv->mNfaP2pServerHandle == NFA_HANDLE_INVALID) - { + if (pSrv->registerWithStack()) { + ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle); + return (true); + } else { ALOGE ("%s: invalid server handle", fn); removeServer (jniHandle); return (false); } - else - { - ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle); - return (true); - } } @@ -290,6 +252,8 @@ void PeerToPeer::removeServer (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::removeServer"; + AutoMutex mutex(mMutex); + for (int i = 0; i < sMax; i++) { if ( (mServers[i] != NULL) && (mServers[i]->mJniHandle == jniHandle) ) @@ -297,7 +261,6 @@ void PeerToPeer::removeServer (tJNI_HANDLE jniHandle) ALOGD ("%s: server jni_handle: %u; nfa_handle: 0x%04x; name: %s; index=%d", fn, jniHandle, mServers[i]->mNfaP2pServerHandle, mServers[i]->mServiceName.c_str(), i); - delete mServers [i]; mServers [i] = NULL; return; } @@ -453,70 +416,24 @@ bool PeerToPeer::accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, { static const char fn [] = "PeerToPeer::accept"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - NfaConn *pConn = NULL; + sp *pConn = NULL; bool stat = false; int ii = 0; - P2pServer *pSrv = NULL; + sp pSrv = NULL; ALOGD ("%s: enter; server jni handle: %u; conn jni handle: %u; maxInfoUnit: %d; recvWindow: %d", fn, serverJniHandle, connJniHandle, maxInfoUnit, recvWindow); - if ((pSrv = findServer (serverJniHandle)) == NULL) + mMutex.lock(); + if ((pSrv = findServerLocked (serverJniHandle)) == NULL) { ALOGE ("%s: unknown server jni handle: %u", fn, serverJniHandle); + mMutex.unlock(); return (false); } + mMutex.unlock(); - // First, find a free connection block to handle the connection - for (ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++) - { - if (pSrv->mServerConn[ii] == NULL) - { - ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; allocate server conn index: %u", fn, - serverJniHandle, connJniHandle, ii); - pSrv->mServerConn[ii] = new NfaConn; - pSrv->mServerConn[ii]->mJniHandle = connJniHandle; - break; - } - } - - if (ii == MAX_NFA_CONNS_PER_SERVER) - { - ALOGE ("%s: fail allocate connection block", fn); - return (false); - } - - { - // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection - SyncEventGuard guard (pSrv->mConnRequestEvent); - ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; wait for incoming connection", fn, - serverJniHandle, connJniHandle, ii); - pSrv->mConnRequestEvent.wait(); - ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X; got incoming connection", fn, - serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); - } - - if (pSrv->mServerConn[ii]->mNfaConnHandle == NFA_HANDLE_INVALID) - { - delete (pSrv->mServerConn[ii]); - pSrv->mServerConn[ii] = NULL; - ALOGD ("%s: no handle assigned", fn); - return (false); - } - - ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X; try accept", fn, - serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); - nfaStat = NFA_P2pAcceptConn (pSrv->mServerConn[ii]->mNfaConnHandle, maxInfoUnit, recvWindow); - - if (nfaStat != NFA_STATUS_OK) - { - ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat); - return (false); - } - - ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; server conn index: %u; nfa conn h: 0x%X", fn, - serverJniHandle, connJniHandle, ii, pSrv->mServerConn[ii]->mNfaConnHandle); - return (true); + return pSrv->accept(serverJniHandle, connJniHandle, maxInfoUnit, recvWindow); } @@ -534,13 +451,16 @@ bool PeerToPeer::deregisterServer (tJNI_HANDLE jniHandle) static const char fn [] = "PeerToPeer::deregisterServer"; ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - P2pServer *pSrv = NULL; + sp pSrv = NULL; - if ((pSrv = findServer (jniHandle)) == NULL) + mMutex.lock(); + if ((pSrv = findServerLocked (jniHandle)) == NULL) { ALOGE ("%s: unknown service handle: %u", fn, jniHandle); + mMutex.unlock(); return (false); } + mMutex.unlock(); { // Server does not call NFA_P2pDisconnect(), so unblock the accept() @@ -579,39 +499,44 @@ bool PeerToPeer::createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) int i = 0; ALOGD ("%s: enter: jni h: %u miu: %u rw: %u", fn, jniHandle, miu, rw); + mMutex.lock(); + sp client = NULL; for (i = 0; i < sMax; i++) { if (mClients[i] == NULL) { - mClients [i] = new P2pClient; + mClients [i] = client = new P2pClient(); - mClients [i]->mClientConn.mJniHandle = jniHandle; - mClients [i]->mClientConn.mMaxInfoUnit = miu; - mClients [i]->mClientConn.mRecvWindow = rw; + mClients [i]->mClientConn->mJniHandle = jniHandle; + mClients [i]->mClientConn->mMaxInfoUnit = miu; + mClients [i]->mClientConn->mRecvWindow = rw; break; } } + mMutex.unlock(); - if (i == sMax) + if (client == NULL) { ALOGE ("%s: fail", fn); return (false); } - ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, mClients[i], jniHandle); + ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, client.get(), jniHandle); - SyncEventGuard guard (mClients[i]->mRegisteringEvent); - NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback); - mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT + { + SyncEventGuard guard (mClients[i]->mRegisteringEvent); + NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback); + mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT + } if (mClients[i]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) { - ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, mClients[i]->mClientConn.mNfaConnHandle); + ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle); return (true); } else { - ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, mClients[i]->mClientConn.mNfaConnHandle); + ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle); removeConn (jniHandle); return (false); } @@ -633,15 +558,15 @@ void PeerToPeer::removeConn(tJNI_HANDLE jniHandle) static const char fn[] = "PeerToPeer::removeConn"; int ii = 0, jj = 0; + AutoMutex mutex(mMutex); // If the connection is a for a client, delete the client itself for (ii = 0; ii < sMax; ii++) { - if (mClients[ii] && (mClients[ii]->mClientConn.mJniHandle == jniHandle)) + if ((mClients[ii] != NULL) && (mClients[ii]->mClientConn->mJniHandle == jniHandle)) { if (mClients[ii]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) NFA_P2pDeregister (mClients[ii]->mNfaP2pClientHandle); - delete mClients[ii]; mClients[ii] = NULL; ALOGD ("%s: deleted client handle: %u index: %u", fn, jniHandle, ii); return; @@ -653,17 +578,8 @@ void PeerToPeer::removeConn(tJNI_HANDLE jniHandle) { if (mServers[ii] != NULL) { - for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) - { - if ( (mServers[ii]->mServerConn[jj] != NULL) - && (mServers[ii]->mServerConn[jj]->mJniHandle == jniHandle) ) - { - ALOGD ("%s: delete server conn jni h: %u; index: %d; server jni h: %u", - fn, mServers[ii]->mServerConn[jj]->mJniHandle, jj, mServers[ii]->mJniHandle); - delete mServers[ii]->mServerConn[jj]; - mServers[ii]->mServerConn[jj] = NULL; - return; - } + if (mServers[ii]->removeServerConnection(jniHandle)) { + return; } } } @@ -731,7 +647,7 @@ bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceN static const char fn [] = "PeerToPeer::createDataLinkConn"; ALOGD ("%s: enter", fn); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - P2pClient *pClient = NULL; + sp pClient = NULL; if ((pClient = findClient (jniHandle)) == NULL) { @@ -745,21 +661,21 @@ bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceN if (serviceName) nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle, - const_cast(serviceName), pClient->mClientConn.mMaxInfoUnit, - pClient->mClientConn.mRecvWindow); + const_cast(serviceName), pClient->mClientConn->mMaxInfoUnit, + pClient->mClientConn->mRecvWindow); else if (destinationSap) nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap, - pClient->mClientConn.mMaxInfoUnit, pClient->mClientConn.mRecvWindow); + pClient->mClientConn->mMaxInfoUnit, pClient->mClientConn->mRecvWindow); if (nfaStat == NFA_STATUS_OK) { - ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient); + ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient.get()); pClient->mConnectingEvent.wait(); } } if (nfaStat == NFA_STATUS_OK) { - if (pClient->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) + if (pClient->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID) { removeConn (jniHandle); nfaStat = NFA_STATUS_FAILED; @@ -788,11 +704,12 @@ bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceN ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pClient *PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) +sp PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) { + AutoMutex mutex(mMutex); for (int i = 0; i < sMax; i++) { - if (mClients[i] && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle)) + if ((mClients[i] != NULL) && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle)) return (mClients[i]); } return (NULL); @@ -809,11 +726,12 @@ P2pClient *PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pClient *PeerToPeer::findClient (tJNI_HANDLE jniHandle) +sp PeerToPeer::findClient (tJNI_HANDLE jniHandle) { + AutoMutex mutex(mMutex); for (int i = 0; i < sMax; i++) { - if (mClients[i] && (mClients[i]->mClientConn.mJniHandle == jniHandle)) + if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mJniHandle == jniHandle)) return (mClients[i]); } return (NULL); @@ -830,11 +748,12 @@ P2pClient *PeerToPeer::findClient (tJNI_HANDLE jniHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -P2pClient *PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) +sp PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) { + AutoMutex mutex(mMutex); for (int i = 0; i < sMax; i++) { - if (mClients[i] && (mClients[i]->mClientConn.mNfaConnHandle == nfaConnHandle)) + if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mNfaConnHandle == nfaConnHandle)) return (mClients[i]); } return (NULL); @@ -851,16 +770,18 @@ P2pClient *PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) +sp PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) { int ii = 0, jj = 0; + AutoMutex mutex(mMutex); // First, look through all the client control blocks for (ii = 0; ii < sMax; ii++) { if ( (mClients[ii] != NULL) - && (mClients[ii]->mClientConn.mNfaConnHandle == nfaConnHandle) ) - return (&mClients[ii]->mClientConn); + && (mClients[ii]->mClientConn->mNfaConnHandle == nfaConnHandle) ) { + return mClients[ii]->mClientConn; + } } // Not found yet. Look through all the server control blocks @@ -868,11 +789,9 @@ NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) { if (mServers[ii] != NULL) { - for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) - { - if ( (mServers[ii]->mServerConn[jj] != NULL) - && (mServers[ii]->mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) - return (mServers[ii]->mServerConn[jj]); + sp conn = mServers[ii]->findServerConnection(nfaConnHandle); + if (conn != NULL) { + return conn; } } } @@ -892,16 +811,18 @@ NfaConn *PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) ** Returns: PeerToPeer object. ** *******************************************************************************/ -NfaConn *PeerToPeer::findConnection (tJNI_HANDLE jniHandle) +sp PeerToPeer::findConnection (tJNI_HANDLE jniHandle) { int ii = 0, jj = 0; + AutoMutex mutex(mMutex); // First, look through all the client control blocks for (ii = 0; ii < sMax; ii++) { if ( (mClients[ii] != NULL) - && (mClients[ii]->mClientConn.mJniHandle == jniHandle) ) - return (&mClients[ii]->mClientConn); + && (mClients[ii]->mClientConn->mJniHandle == jniHandle) ) { + return mClients[ii]->mClientConn; + } } // Not found yet. Look through all the server control blocks @@ -909,11 +830,9 @@ NfaConn *PeerToPeer::findConnection (tJNI_HANDLE jniHandle) { if (mServers[ii] != NULL) { - for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) - { - if ( (mServers[ii]->mServerConn[jj] != NULL) - && (mServers[ii]->mServerConn[jj]->mJniHandle == jniHandle) ) - return (mServers[ii]->mServerConn[jj]); + sp conn = mServers[ii]->findServerConnection(jniHandle); + if (conn != NULL) { + return conn; } } } @@ -939,7 +858,7 @@ bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) { static const char fn [] = "PeerToPeer::send"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - NfaConn *pConn = NULL; + sp pConn = NULL; if ((pConn = findConnection (jniHandle)) == NULL) { @@ -993,7 +912,7 @@ bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen { static const char fn [] = "PeerToPeer::receive"; ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); - NfaConn *pConn = NULL; + sp pConn = NULL; tNFA_STATUS stat = NFA_STATUS_FAILED; UINT32 actualDataLen2 = 0; BOOLEAN isMoreData = TRUE; @@ -1043,8 +962,8 @@ bool PeerToPeer::disconnectConnOriented (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::disconnectConnOriented"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; - P2pClient *pClient = NULL; - NfaConn *pConn = NULL; + sp pClient = NULL; + sp pConn = NULL; ALOGD ("%s: enter; jni handle: %u", fn, jniHandle); @@ -1105,7 +1024,7 @@ bool PeerToPeer::disconnectConnOriented (tJNI_HANDLE jniHandle) UINT16 PeerToPeer::getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit"; - NfaConn *pConn = NULL; + sp pConn = NULL; if ((pConn = findConnection(jniHandle)) == NULL) { @@ -1131,7 +1050,7 @@ UINT8 PeerToPeer::getRemoteRecvWindow (tJNI_HANDLE jniHandle) { static const char fn [] = "PeerToPeer::getRemoteRecvWindow"; ALOGD ("%s: client jni handle: %u", fn, jniHandle); - NfaConn *pConn = NULL; + sp pConn = NULL; if ((pConn = findConnection(jniHandle)) == NULL) { @@ -1218,6 +1137,7 @@ void PeerToPeer::handleNfcOnOff (bool isOn) mIsP2pListening = false; // In both cases, P2P will not be listening + AutoMutex mutex(mMutex); if (isOn) { // Start with no clients or servers @@ -1233,21 +1153,21 @@ void PeerToPeer::handleNfcOnOff (bool isOn) { if (mClients[ii] != NULL) { - if (mClients[ii]->mClientConn.mNfaConnHandle == NFA_HANDLE_INVALID) + if (mClients[ii]->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID) { SyncEventGuard guard (mClients[ii]->mConnectingEvent); mClients[ii]->mConnectingEvent.notifyOne(); } else { - mClients[ii]->mClientConn.mNfaConnHandle = NFA_HANDLE_INVALID; + mClients[ii]->mClientConn->mNfaConnHandle = NFA_HANDLE_INVALID; { - SyncEventGuard guard1 (mClients[ii]->mClientConn.mCongEvent); - mClients[ii]->mClientConn.mCongEvent.notifyOne (); //unblock send() + SyncEventGuard guard1 (mClients[ii]->mClientConn->mCongEvent); + mClients[ii]->mClientConn->mCongEvent.notifyOne (); //unblock send() } { - SyncEventGuard guard2 (mClients[ii]->mClientConn.mReadEvent); - mClients[ii]->mClientConn.mReadEvent.notifyOne (); //unblock receive() + SyncEventGuard guard2 (mClients[ii]->mClientConn->mReadEvent); + mClients[ii]->mClientConn->mReadEvent.notifyOne (); //unblock receive() } } } @@ -1258,21 +1178,7 @@ void PeerToPeer::handleNfcOnOff (bool isOn) { if (mServers[ii] != NULL) { - for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) - { - if (mServers[ii]->mServerConn[jj] != NULL) - { - mServers[ii]->mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID; - { - SyncEventGuard guard1 (mServers[ii]->mServerConn[jj]->mCongEvent); - mServers[ii]->mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested) - } - { - SyncEventGuard guard2 (mServers[ii]->mServerConn[jj]->mReadEvent); - mServers[ii]->mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive() - } - } - } + mServers[ii]->unblockAll(); } } //loop @@ -1295,8 +1201,8 @@ void PeerToPeer::handleNfcOnOff (bool isOn) void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) { static const char fn [] = "PeerToPeer::nfaServerCallback"; - P2pServer *pSrv = NULL; - NfaConn *pConn = NULL; + sp pSrv = NULL; + sp pConn = NULL; ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent); @@ -1306,7 +1212,10 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev ALOGD ("%s: NFA_P2P_REG_SERVER_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, eventData->reg_server.server_handle, eventData->reg_server.server_sap, eventData->reg_server.service_name); - if ((pSrv = sP2p.findServer(eventData->reg_server.service_name)) == NULL) + sP2p.mMutex.lock(); + pSrv = sP2p.findServerLocked(eventData->reg_server.service_name); + sP2p.mMutex.unlock(); + if (pSrv == NULL) { ALOGE ("%s: NFA_P2P_REG_SERVER_EVT for unknown service: %s", fn, eventData->reg_server.service_name); } @@ -1330,7 +1239,10 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; nfa server h=0x%04x; nfa conn h=0x%04x; remote sap=0x%02x", fn, eventData->conn_req.server_handle, eventData->conn_req.conn_handle, eventData->conn_req.remote_sap); - if ((pSrv = sP2p.findServer(eventData->conn_req.server_handle)) == NULL) + sP2p.mMutex.lock(); + pSrv = sP2p.findServerLocked(eventData->conn_req.server_handle); + sP2p.mMutex.unlock(); + if (pSrv == NULL) { ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn); return; @@ -1338,7 +1250,7 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u", fn, pSrv->mJniHandle); // Look for a connection block that is waiting (handle invalid) - if ((pConn = pSrv->findServerConnection(NFA_HANDLE_INVALID)) == NULL) + if ((pConn = pSrv->findServerConnection((tNFA_HANDLE) NFA_HANDLE_INVALID)) == NULL) { ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; server not listening", fn); } @@ -1446,8 +1358,8 @@ void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) { static const char fn [] = "PeerToPeer::nfaClientCallback"; - NfaConn *pConn = NULL; - P2pClient *pClient = NULL; + sp pConn = NULL; + sp pClient = NULL; ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent); @@ -1461,7 +1373,7 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev } else { - ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient); + ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient.get()); SyncEventGuard guard (pClient->mRegisteringEvent); pClient->mNfaP2pClientHandle = eventData->reg_client.client_handle; @@ -1477,7 +1389,7 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev } else { - ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient); + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient.get()); } break; @@ -1494,12 +1406,12 @@ void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* ev else { ALOGD ("%s: NFA_P2P_CONNECTED_EVT; client_handle=0x%04x conn_handle: 0x%04x remote sap=0x%X pClient: 0x%p", fn, - eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient); + eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient.get()); SyncEventGuard guard (pClient->mConnectingEvent); - pClient->mClientConn.mNfaConnHandle = eventData->connected.conn_handle; - pClient->mClientConn.mRemoteMaxInfoUnit = eventData->connected.remote_miu; - pClient->mClientConn.mRemoteRecvWindow = eventData->connected.remote_rw; + pClient->mClientConn->mNfaConnHandle = eventData->connected.conn_handle; + pClient->mClientConn->mRemoteMaxInfoUnit = eventData->connected.remote_miu; + pClient->mClientConn->mRemoteRecvWindow = eventData->connected.remote_rw; pClient->mConnectingEvent.notifyOne(); //unblock createDataLinkConn() } break; @@ -1641,13 +1553,147 @@ PeerToPeer::tJNI_HANDLE PeerToPeer::getNewJniHandle () ** Returns: None ** *******************************************************************************/ -P2pServer::P2pServer() +P2pServer::P2pServer(PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName) : mNfaP2pServerHandle (NFA_HANDLE_INVALID), - mJniHandle (0) + mJniHandle (jniHandle) { + mServiceName.assign (serviceName); + memset (mServerConn, 0, sizeof(mServerConn)); } +bool P2pServer::registerWithStack() +{ + static const char fn [] = "P2pServer::registerWithStack"; + ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, mServiceName.c_str(), mJniHandle); + tNFA_STATUS stat = NFA_STATUS_OK; + UINT8 serverSap = NFA_P2P_ANY_SAP; + + /********************** + default values for all LLCP parameters: + - Local Link MIU (LLCP_MIU) + - Option parameter (LLCP_OPT_VALUE) + - Response Waiting Time Index (LLCP_WAITING_TIME) + - Local Link Timeout (LLCP_LTO_VALUE) + - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT) + - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT) + - Delay SYMM response (LLCP_DELAY_RESP_TIME) + - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) + - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) + ************************/ + stat = NFA_P2pSetLLCPConfig (LLCP_MIU, + LLCP_OPT_VALUE, + LLCP_WAITING_TIME, + LLCP_LTO_VALUE, + 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator + 0, //use 0 for infinite timeout for symmetry procedure when acting as target + LLCP_DELAY_RESP_TIME, + LLCP_DATA_LINK_CONNECTION_TOUT, + LLCP_DELAY_TIME_TO_SEND_FIRST_PDU); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat); + + if (sSnepServiceName.compare(mServiceName) == 0) + serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 + + { + SyncEventGuard guard (mRegServerEvent); + stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast(mServiceName.c_str()), + PeerToPeer::nfaServerCallback); + if (stat != NFA_STATUS_OK) + { + ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); + return (false); + } + ALOGD ("%s: wait for listen-completion event", fn); + // Wait for NFA_P2P_REG_SERVER_EVT + mRegServerEvent.wait (); + } + + return (mNfaP2pServerHandle != NFA_HANDLE_INVALID); +} + +bool P2pServer::accept(PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle, + int maxInfoUnit, int recvWindow) +{ + static const char fn [] = "P2pServer::accept"; + tNFA_STATUS nfaStat = NFA_STATUS_OK; + + sp connection = allocateConnection(connJniHandle); + if (connection == NULL) { + ALOGE ("%s: failed to allocate new server connection", fn); + return false; + } + + { + // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection + SyncEventGuard guard (mConnRequestEvent); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; wait for incoming connection", fn, + serverJniHandle, connJniHandle); + mConnRequestEvent.wait(); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; got incoming connection", fn, + serverJniHandle, connJniHandle, connection->mNfaConnHandle); + } + + if (connection->mNfaConnHandle == NFA_HANDLE_INVALID) + { + removeServerConnection(connJniHandle); + ALOGD ("%s: no handle assigned", fn); + return (false); + } + + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; try accept", fn, + serverJniHandle, connJniHandle, connection->mNfaConnHandle); + nfaStat = NFA_P2pAcceptConn (connection->mNfaConnHandle, maxInfoUnit, recvWindow); + + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat); + return (false); + } + + ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X", fn, + serverJniHandle, connJniHandle, connection->mNfaConnHandle); + return (true); +} + +void P2pServer::unblockAll() +{ + AutoMutex mutex(mMutex); + for (int jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if (mServerConn[jj] != NULL) + { + mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mServerConn[jj]->mCongEvent); + mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested) + } + { + SyncEventGuard guard2 (mServerConn[jj]->mReadEvent); + mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive() + } + } + } +} + +sp P2pServer::allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle) +{ + AutoMutex mutex(mMutex); + // First, find a free connection block to handle the connection + for (int ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++) + { + if (mServerConn[ii] == NULL) + { + mServerConn[ii] = new NfaConn; + mServerConn[ii]->mJniHandle = jniHandle; + return mServerConn[ii]; + } + } + + return NULL; +} + /******************************************************************************* ** @@ -1659,10 +1705,11 @@ P2pServer::P2pServer() ** Returns: P2pServer object. ** *******************************************************************************/ -NfaConn *P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) +sp P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) { int jj = 0; + AutoMutex mutex(mMutex); for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) { if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) @@ -1673,7 +1720,57 @@ NfaConn *P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) return (NULL); } +/******************************************************************************* +** +** Function: findServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +sp P2pServer::findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle) +{ + int jj = 0; + + AutoMutex mutex(mMutex); + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) ) + return (mServerConn[jj]); + } + + // If here, not found + return (NULL); +} + +/******************************************************************************* +** +** Function: removeServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +bool P2pServer::removeServerConnection (PeerToPeer::tJNI_HANDLE jniHandle) +{ + int jj = 0; + AutoMutex mutex(mMutex); + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) ) { + mServerConn[jj] = NULL; + return true; + } + } + + // If here, not found + return false; +} ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// @@ -1691,6 +1788,7 @@ P2pClient::P2pClient () : mNfaP2pClientHandle (NFA_HANDLE_INVALID), mIsConnecting (false) { + mClientConn = new NfaConn(); } diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index 040ca78..951b69e 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -9,6 +9,8 @@ ** *****************************************************************************/ #pragma once +#include +#include #include "SyncEvent.h" #include "NfcJniUtil.h" #include @@ -23,7 +25,6 @@ class P2pClient; class NfaConn; #define MAX_NFA_CONNS_PER_SERVER 5 - /***************************************************************************** ** ** Name: PeerToPeer @@ -36,7 +37,6 @@ class PeerToPeer public: typedef unsigned int tJNI_HANDLE; - /******************************************************************************* ** ** Function: PeerToPeer @@ -331,26 +331,6 @@ public: *******************************************************************************/ tJNI_HANDLE getNewJniHandle (); - -private: - static const int sMax = 10; - static PeerToPeer sP2p; - static const std::string sSnepServiceName; - static const std::string sNppServiceName; - UINT16 mRemoteWKS; // Peer's well known services - bool mIsP2pListening; // If P2P listening is enabled or not - tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask - tJNI_HANDLE mNextJniHandle; - - P2pServer *mServers [sMax]; - P2pClient *mClients [sMax]; - SyncEvent mSetTechEvent; // completion event for NFA_SetP2pListenTech() - SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer() - SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient() - Mutex mDisconnectMutex; // synchronize the disconnect operation - Mutex mNewJniHandleMutex; // synchronize the creation of a new JNI handle - - /******************************************************************************* ** ** Function: nfaServerCallback @@ -378,6 +358,31 @@ private: *******************************************************************************/ static void nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData); +private: + static const int sMax = 10; + static PeerToPeer sP2p; + + // Variables below only accessed from a single thread + UINT16 mRemoteWKS; // Peer's well known services + bool mIsP2pListening; // If P2P listening is enabled or not + tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask + + // Variable below is protected by mNewJniHandleMutex + tJNI_HANDLE mNextJniHandle; + + // Variables below protected by mMutex + // A note on locking order: mMutex in PeerToPeer is *ALWAYS* + // locked before any locks / guards in P2pServer / P2pClient + Mutex mMutex; + android::sp mServers [sMax]; + android::sp mClients [sMax]; + + // Synchronization variables + SyncEvent mSetTechEvent; // completion event for NFA_SetP2pListenTech() + SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer() + SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient() + Mutex mDisconnectMutex; // synchronize the disconnect operation + Mutex mNewJniHandleMutex; // synchronize the creation of a new JNI handle /******************************************************************************* ** @@ -417,7 +422,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pServer *findServer (tNFA_HANDLE nfaP2pServerHandle); + android::sp findServerLocked (tNFA_HANDLE nfaP2pServerHandle); /******************************************************************************* @@ -430,7 +435,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pServer *findServer (tJNI_HANDLE jniHandle); + android::sp findServerLocked (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -443,7 +448,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pServer *findServer (const char *serviceName); + android::sp findServerLocked (const char *serviceName); /******************************************************************************* @@ -497,7 +502,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pClient *findClient (tNFA_HANDLE nfaConnHandle); + android::sp findClient (tNFA_HANDLE nfaConnHandle); /******************************************************************************* @@ -510,7 +515,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pClient *findClient (tJNI_HANDLE jniHandle); + android::sp findClient (tJNI_HANDLE jniHandle); /******************************************************************************* @@ -523,7 +528,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - P2pClient *findClientCon (tNFA_HANDLE nfaConnHandle); + android::sp findClientCon (tNFA_HANDLE nfaConnHandle); /******************************************************************************* @@ -536,7 +541,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - NfaConn *findConnection (tNFA_HANDLE nfaConnHandle); + android::sp findConnection (tNFA_HANDLE nfaConnHandle); /******************************************************************************* @@ -549,7 +554,7 @@ private: ** Returns: PeerToPeer object. ** *******************************************************************************/ - NfaConn *findConnection (tJNI_HANDLE jniHandle); + android::sp findConnection (tJNI_HANDLE jniHandle); }; @@ -560,11 +565,11 @@ private: ** Description: Store information about a connection related to a peer. ** *****************************************************************************/ -class NfaConn +class NfaConn : public android::RefBase { public: tNFA_HANDLE mNfaConnHandle; // NFA handle of the P2P connection - PeerToPeer::tJNI_HANDLE mJniHandle; // JNI handle of the P2P connection + PeerToPeer::tJNI_HANDLE mJniHandle; // JNI handle of the P2P connection UINT16 mMaxInfoUnit; UINT8 mRecvWindow; UINT16 mRemoteMaxInfoUnit; @@ -594,15 +599,16 @@ public: ** Description: Store information about an in-bound connection from a peer. ** *****************************************************************************/ -class P2pServer +class P2pServer : public android::RefBase { public: + static const std::string sSnepServiceName; + tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server - PeerToPeer::tJNI_HANDLE mJniHandle; // JNI Handle + PeerToPeer::tJNI_HANDLE mJniHandle; // JNI Handle SyncEvent mRegServerEvent; // for NFA_P2pRegisterServer() SyncEvent mConnRequestEvent; // for accept() std::string mServiceName; - NfaConn *mServerConn[MAX_NFA_CONNS_PER_SERVER]; /******************************************************************************* ** @@ -613,8 +619,45 @@ public: ** Returns: None ** *******************************************************************************/ - P2pServer (); + P2pServer (PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName); + /******************************************************************************* + ** + ** Function: registerWithStack + ** + ** Description: Register this server with the stack. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool registerWithStack(); + + /******************************************************************************* + ** + ** Function: accept + ** + ** Description: Accept a peer's request to connect. + ** serverJniHandle: Server's handle. + ** connJniHandle: Connection handle. + ** maxInfoUnit: Maximum information unit. + ** recvWindow: Receive window size. + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + bool accept (PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle, + int maxInfoUnit, int recvWindow); + + /******************************************************************************* + ** + ** Function: unblockAll + ** + ** Description: Unblocks all server connections + ** + ** Returns: True if ok. + ** + *******************************************************************************/ + void unblockAll(); /******************************************************************************* ** @@ -626,7 +669,49 @@ public: ** Returns: P2pServer object. ** *******************************************************************************/ - NfaConn *findServerConnection (tNFA_HANDLE nfaConnHandle); + android::sp findServerConnection (tNFA_HANDLE nfaConnHandle); + + /******************************************************************************* + ** + ** Function: findServerConnection + ** + ** Description: Find a P2pServer that has the handle. + ** jniHandle: JNI connection handle. + ** + ** Returns: P2pServer object. + ** + *******************************************************************************/ + android::sp findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle); + + /******************************************************************************* + ** + ** Function: removeServerConnection + ** + ** Description: Remove a server connection with the provided handle. + ** jniHandle: JNI connection handle. + ** + ** Returns: True if connection found and removed. + ** + *******************************************************************************/ + bool removeServerConnection(PeerToPeer::tJNI_HANDLE jniHandle); + +private: + Mutex mMutex; + // mServerConn is protected by mMutex + android::sp mServerConn[MAX_NFA_CONNS_PER_SERVER]; + + /******************************************************************************* + ** + ** Function: allocateConnection + ** + ** Description: Allocate a new connection to accept on + ** jniHandle: JNI connection handle. + ** + ** Returns: Allocated connection object + ** NULL if the maximum number of connections was reached + ** + *******************************************************************************/ + android::sp allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle); }; @@ -637,15 +722,15 @@ public: ** Description: Store information about an out-bound connection to a peer. ** *****************************************************************************/ -class P2pClient +class P2pClient : public android::RefBase { public: - tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client - bool mIsConnecting; // Set true while connecting - NfaConn mClientConn; - SyncEvent mRegisteringEvent; // For client registration - SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap() - SyncEvent mSnepEvent; // To wait for SNEP completion + tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client + bool mIsConnecting; // Set true while connecting + android::sp mClientConn; + SyncEvent mRegisteringEvent; // For client registration + SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap() + SyncEvent mSnepEvent; // To wait for SNEP completion /******************************************************************************* ** @@ -669,5 +754,17 @@ public: ** *******************************************************************************/ ~P2pClient (); + + + /******************************************************************************* + ** + ** Function: unblock + ** + ** Description: Unblocks any threads that are locked on this connection + ** + ** Returns: None + ** + *******************************************************************************/ + void unblock(); }; -- cgit v1.1 From b64ce3632295a51a83f0d6b2aae7a5d357eaa86d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 18 Sep 2012 18:08:36 -0700 Subject: Merge NFCEE wakelocks. These were just in for debugging. Bug: 6963484 Change-Id: Iac4b9185a615243783614429869f3f34b5cba82f --- src/com/android/nfc/NfcService.java | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 3acfa1c..e8fc9e4 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -187,9 +187,8 @@ public class NfcService extends Application implements DeviceHostListener { private SharedPreferences mPrefs; private SharedPreferences.Editor mPrefsEditor; private PowerManager.WakeLock mRoutingWakeLock; - private PowerManager.WakeLock mOpenWakeLock; - private PowerManager.WakeLock mDisconnectWakeLock; - private PowerManager.WakeLock mTransceiveWakeLock; + private PowerManager.WakeLock mEeWakeLock; + int mStartSound; int mEndSound; int mErrorSound; @@ -323,16 +322,10 @@ public class NfcService extends Application implements DeviceHostListener { mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); - // TODO(mikey|maco): consolidate as a single wakelock when individual - // stats are no longer useful. mRoutingWakeLock = mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock"); - mOpenWakeLock = mPowerManager.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mOpenWakeLock"); - mDisconnectWakeLock = mPowerManager.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mDisconnectWakeLock"); - mTransceiveWakeLock = mPowerManager.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mTransceiveWakeLock"); + mEeWakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock"); mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); mScreenState = checkScreenState(); @@ -417,20 +410,20 @@ public class NfcService extends Application implements DeviceHostListener { } int doOpenSecureElementConnection() { - mOpenWakeLock.acquire(); + mEeWakeLock.acquire(); try { return mSecureElement.doOpenSecureElementConnection(); } finally { - mOpenWakeLock.release(); + mEeWakeLock.release(); } } byte[] doTransceive(int handle, byte[] cmd) { - mTransceiveWakeLock.acquire(); + mEeWakeLock.acquire(); try { return doTransceiveNoLock(handle, cmd); } finally { - mTransceiveWakeLock.release(); + mEeWakeLock.release(); } } @@ -439,11 +432,11 @@ public class NfcService extends Application implements DeviceHostListener { } void doDisconnect(int handle) { - mDisconnectWakeLock.acquire(); + mEeWakeLock.acquire(); try { mSecureElement.doDisconnect(handle); } finally { - mDisconnectWakeLock.release(); + mEeWakeLock.release(); } } @@ -640,7 +633,7 @@ public class NfcService extends Application implements DeviceHostListener { } try { - mTransceiveWakeLock.acquire(); + mEeWakeLock.acquire(); try { mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000); @@ -654,7 +647,7 @@ public class NfcService extends Application implements DeviceHostListener { mDeviceHost.resetTimeouts(); } finally { - mTransceiveWakeLock.release(); + mEeWakeLock.release(); } } finally { doDisconnect(handle); -- cgit v1.1 From b95ef0b6e86a4fcfe2474ccaea0925f69a462bec Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Wed, 19 Sep 2012 18:18:30 -0400 Subject: copyright by The Android Open Source Project Bug: 7125646 Change-Id: I4de457f982857be315d65386f431d5eafcd8af02 --- nci/jni/CondVar.cpp | 29 ++++++++++------ nci/jni/CondVar.h | 31 +++++++++++------ nci/jni/DataQueue.cpp | 29 ++++++++++------ nci/jni/DataQueue.h | 29 ++++++++++------ nci/jni/HostAidRouter.cpp | 29 ++++++++++------ nci/jni/HostAidRouter.h | 29 ++++++++++------ nci/jni/IntervalTimer.cpp | 29 ++++++++++------ nci/jni/IntervalTimer.h | 29 ++++++++++------ nci/jni/JavaClassConstants.h | 3 +- nci/jni/Mutex.cpp | 29 ++++++++++------ nci/jni/Mutex.h | 29 ++++++++++------ nci/jni/NativeLlcpConnectionlessSocket.cpp | 3 +- nci/jni/NativeLlcpServiceSocket.cpp | 3 +- nci/jni/NativeLlcpSocket.cpp | 3 +- nci/jni/NativeNfcManager.cpp | 3 +- nci/jni/NativeNfcTag.cpp | 19 +---------- nci/jni/NativeP2pDevice.cpp | 3 +- nci/jni/NativeSecureElement.cpp | 3 +- nci/jni/NfcJniUtil.cpp | 3 +- nci/jni/NfcJniUtil.h | 3 +- nci/jni/NfcTag.cpp | 55 +++++++++++++++++------------- nci/jni/NfcTag.h | 29 ++++++++++------ nci/jni/PeerToPeer.cpp | 29 ++++++++++------ nci/jni/PeerToPeer.h | 29 ++++++++++------ nci/jni/PowerSwitch.cpp | 29 ++++++++++------ nci/jni/PowerSwitch.h | 29 ++++++++++------ nci/jni/RouteDataSet.cpp | 29 ++++++++++------ nci/jni/RouteDataSet.h | 29 ++++++++++------ nci/jni/SecureElement.cpp | 31 +++++++++++------ nci/jni/SecureElement.h | 31 +++++++++++------ nci/jni/SyncEvent.h | 30 ++++++++++------ 31 files changed, 425 insertions(+), 263 deletions(-) diff --git a/nci/jni/CondVar.cpp b/nci/jni/CondVar.cpp index 1156344..e69cc46 100644 --- a/nci/jni/CondVar.cpp +++ b/nci/jni/CondVar.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: CondVar.cpp -** -** Description: Encapsulate a condition variable for thread synchronization. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Encapsulate a condition variable for thread synchronization. + */ #include "CondVar.h" #include "NfcJniUtil.h" diff --git a/nci/jni/CondVar.h b/nci/jni/CondVar.h index eca17aa..c286d5c 100644 --- a/nci/jni/CondVar.h +++ b/nci/jni/CondVar.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: CondVar.h -** -** Description: Encapsulate a condition variable for thread synchronization. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Encapsulate a condition variable for thread synchronization. + */ #pragma once #include @@ -79,4 +88,4 @@ public: private: pthread_cond_t mCondition; -}; \ No newline at end of file +}; diff --git a/nci/jni/DataQueue.cpp b/nci/jni/DataQueue.cpp index ab94734..caa2575 100644 --- a/nci/jni/DataQueue.cpp +++ b/nci/jni/DataQueue.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: DataQueue.cpp -** -** Description: Store data bytes in a variable-size queue. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Store data bytes in a variable-size queue. + */ #include "DataQueue.h" diff --git a/nci/jni/DataQueue.h b/nci/jni/DataQueue.h index 4bb6bda..bfd415c 100644 --- a/nci/jni/DataQueue.h +++ b/nci/jni/DataQueue.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: DataQueue.h -** -** Description: Store data bytes in a variable-size queue. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Store data bytes in a variable-size queue. + */ #pragma once #include "NfcJniUtil.h" diff --git a/nci/jni/HostAidRouter.cpp b/nci/jni/HostAidRouter.cpp index 5b32608..0b511f8 100644 --- a/nci/jni/HostAidRouter.cpp +++ b/nci/jni/HostAidRouter.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: HostAidRouter.cpp -** -** Description: Manage listen-mode AID routing to the host. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Manage listen-mode AID routing to the host. + */ #include "OverrideLog.h" #include "HostAidRouter.h" #include "config.h" diff --git a/nci/jni/HostAidRouter.h b/nci/jni/HostAidRouter.h index 409df93..f653aa9 100644 --- a/nci/jni/HostAidRouter.h +++ b/nci/jni/HostAidRouter.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: HostAidRouter.h -** -** Description: Manage listen-mode AID routing to the host. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Manage listen-mode AID routing to the host. + */ #pragma once #include "SyncEvent.h" #include "NfcJniUtil.h" diff --git a/nci/jni/IntervalTimer.cpp b/nci/jni/IntervalTimer.cpp index 304fa7e..f71ca8e 100644 --- a/nci/jni/IntervalTimer.cpp +++ b/nci/jni/IntervalTimer.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: IntervalTimer.cpp -** -** Description: Asynchronous interval timer. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Asynchronous interval timer. + */ #include "IntervalTimer.h" #include "OverrideLog.h" diff --git a/nci/jni/IntervalTimer.h b/nci/jni/IntervalTimer.h index e3ec1c6..66e345d 100644 --- a/nci/jni/IntervalTimer.h +++ b/nci/jni/IntervalTimer.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: IntervalTimer.h -** -** Description: Asynchronous interval timer. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Asynchronous interval timer. + */ #include diff --git a/nci/jni/JavaClassConstants.h b/nci/jni/JavaClassConstants.h index fb71757..64244c3 100644 --- a/nci/jni/JavaClassConstants.h +++ b/nci/jni/JavaClassConstants.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp index 6ccb87b..c0b12c0 100644 --- a/nci/jni/Mutex.cpp +++ b/nci/jni/Mutex.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: Mutex.cpp -** -** Description: Encapsulate a mutex for thread synchronization. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Encapsulate a mutex for thread synchronization. + */ #include "Mutex.h" #include "NfcJniUtil.h" diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h index 1b500ee..45f42de 100644 --- a/nci/jni/Mutex.h +++ b/nci/jni/Mutex.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: Mutex.h -** -** Description: Encapsulate a mutex for thread synchronization. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Encapsulate a mutex for thread synchronization. + */ #pragma once #include diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp index a278844..ecc57e3 100644 --- a/nci/jni/NativeLlcpConnectionlessSocket.cpp +++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp index c4a655e..e1c2bb5 100644 --- a/nci/jni/NativeLlcpServiceSocket.cpp +++ b/nci/jni/NativeLlcpServiceSocket.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp index f5daff0..74a59b9 100644 --- a/nci/jni/NativeLlcpSocket.cpp +++ b/nci/jni/NativeLlcpSocket.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index fcab063..c3e76fa 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index d4281ce..e7352c5 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -798,22 +797,6 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da } NfcTag& natTag = NfcTag::getInstance (); - if (natTag.mNumTechList >= 2 && natTag.mTechList[0] == TARGET_TYPE_ISO14443_3A) - { - if (natTag.mTechList[1] == TARGET_TYPE_MIFARE_CLASSIC) - { - // MifareClassic tag, we do not support transceive for this - if (statusTargetLost) - { - targetLost = e->GetIntArrayElements (statusTargetLost, 0); - if (targetLost) - *targetLost = 2; //causes NFC service to throw IOException - e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0); - } - ALOGD ("%s: transceive not supported for MifareClassic tag", __FUNCTION__); - return NULL; - } - } // get input buffer and length from java call buf = (uint8_t *) e->GetByteArrayElements (data, NULL); diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp index 216edb1..57f9dad 100644 --- a/nci/jni/NativeP2pDevice.cpp +++ b/nci/jni/NativeP2pDevice.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp index 9fa27e3..8379162 100755 --- a/nci/jni/NativeSecureElement.cpp +++ b/nci/jni/NativeSecureElement.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NfcJniUtil.cpp b/nci/jni/NfcJniUtil.cpp index 7619f30..9921cae 100755 --- a/nci/jni/NfcJniUtil.cpp +++ b/nci/jni/NfcJniUtil.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NfcJniUtil.h b/nci/jni/NfcJniUtil.h index 90f2cab..8caa0b8 100755 --- a/nci/jni/NfcJniUtil.h +++ b/nci/jni/NfcJniUtil.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Broadcom Corporation + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp index ed140f6..e996fdd 100755 --- a/nci/jni/NfcTag.cpp +++ b/nci/jni/NfcTag.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: NfcTag.cpp -** -** Description: Tag-reading, tag-writing operations. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Tag-reading, tag-writing operations. + */ #include "OverrideLog.h" #include "NfcTag.h" #include "JavaClassConstants.h" @@ -249,16 +258,15 @@ void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData) rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 || rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08) { - //Mifare Ultralight or mifare Classic - mNumTechList++; - mTechHandles [mNumTechList] = rfDetail.rf_disc_id; - mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; - //save the stack's data structure for interpretation later - memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0) + { + mNumTechList++; + mTechHandles [mNumTechList] = rfDetail.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = rfDetail.protocol; + //save the stack's data structure for interpretation later + memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param)); mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API - else - mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API + } } } break; @@ -357,13 +365,14 @@ void NfcTag::discoverTechnologies (tNFA_DISC_RESULT& discoveryData) case NFC_PROTOCOL_T2T: mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API //type-2 tags are identitical to Mifare Ultralight, so Ultralight is also discovered - mNumTechList++; - mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; - mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; if (discovery_ntf.rf_tech_param.param.pa.sel_rsp == 0) + { + // mifare Ultralight + mNumTechList++; + mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id; + mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol; mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API - else - mTechList [mNumTechList] = TARGET_TYPE_MIFARE_CLASSIC; //is TagTechnology.MIFARE_CLASSIC by Java API + } //save the stack's data structure for interpretation later memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param)); diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h index 276a649..76a6bb7 100755 --- a/nci/jni/NfcTag.h +++ b/nci/jni/NfcTag.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: NfcTag.h -** -** Description: Tag-reading, tag-writing operations. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Tag-reading, tag-writing operations. + */ #pragma once #include "SyncEvent.h" diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 78132b8..13b5a60 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: PeerToPeer.cpp -** -** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Communicate with a peer using NFC-DEP, LLCP, SNEP. + */ #include "OverrideLog.h" #include "PeerToPeer.h" #include "NfcJniUtil.h" diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h index 951b69e..3e8ffec 100644 --- a/nci/jni/PeerToPeer.h +++ b/nci/jni/PeerToPeer.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: PeerToPeer.h -** -** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Communicate with a peer using NFC-DEP, LLCP, SNEP. + */ #pragma once #include #include diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp index 11d1abe..6c1df71 100755 --- a/nci/jni/PowerSwitch.cpp +++ b/nci/jni/PowerSwitch.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: PowerSwitch.cpp -** -** Description: Adjust the controller's power states. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Adjust the controller's power states. + */ #include "OverrideLog.h" #include "PowerSwitch.h" #include "NfcJniUtil.h" diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h index 2e6b604..5c939ee 100755 --- a/nci/jni/PowerSwitch.h +++ b/nci/jni/PowerSwitch.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: PowerSwitch.h -** -** Description: Adjust the controller's power states. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Adjust the controller's power states. + */ #pragma once #include "nfa_api.h" #include "SyncEvent.h" diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp index 8985a90..1458776 100644 --- a/nci/jni/RouteDataSet.cpp +++ b/nci/jni/RouteDataSet.cpp @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: RouteDataSet.cpp -** -** Description: Import and export general routing data using a XML file. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Import and export general routing data using a XML file. + */ #include "OverrideLog.h" #include "RouteDataSet.h" #include "libxml/xmlmemory.h" diff --git a/nci/jni/RouteDataSet.h b/nci/jni/RouteDataSet.h index 63c88e4..d937dec 100644 --- a/nci/jni/RouteDataSet.h +++ b/nci/jni/RouteDataSet.h @@ -1,13 +1,22 @@ -/***************************************************************************** -** -** Name: RouteDataSet.h -** -** Description: Import and export general routing data using a XML file. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Import and export general routing data using a XML file. + */ #pragma once #include "NfcJniUtil.h" #include "nfa_api.h" diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 5008998..ff84bcc 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -1,14 +1,23 @@ -/***************************************************************************** -** -** Name: SecureElement.cpp -** -** Description: Communicate with secure elements that are attached -** to the NFC controller. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Communicate with secure elements that are attached to the NFC + * controller. + */ #include #include #include "OverrideLog.h" diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index bfa54cc..b887513 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -1,14 +1,23 @@ -/***************************************************************************** -** -** Name: SecureElement.h -** -** Description: Communicate with secure elements that are attached -** to the NFC controller. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Communicate with secure elements that are attached to the NFC + * controller. + */ #pragma once #include "SyncEvent.h" #include "DataQueue.h" diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h index 146b3ce..5fd389e 100644 --- a/nci/jni/SyncEvent.h +++ b/nci/jni/SyncEvent.h @@ -1,14 +1,22 @@ -/***************************************************************************** -** -** Name: SyncEvent.h -** -** Description: Synchronize two or more threads using a condition variable -** and a mutex. -** -** Copyright (c) 2012, Broadcom Corp., All Rights Reserved. -** Proprietary and confidential. -** -*****************************************************************************/ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Synchronize two or more threads using a condition variable and a mutex. + */ #pragma once #include "CondVar.h" #include "Mutex.h" -- cgit v1.1 From 0873b0517eb1ab968be90f66f0b3cdbbeb62f78c Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Thu, 20 Sep 2012 14:39:22 -0400 Subject: Grant license Bug: 7125646 Change-Id: If700eb3cdd85e9ee08701d2dd8971ce2500a834d --- nci/jni/IMPORTANT_LICENSE | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 nci/jni/IMPORTANT_LICENSE diff --git a/nci/jni/IMPORTANT_LICENSE b/nci/jni/IMPORTANT_LICENSE new file mode 100644 index 0000000..2cc9a94 --- /dev/null +++ b/nci/jni/IMPORTANT_LICENSE @@ -0,0 +1,50 @@ + +Copyright (C) 1999-2012 Broadcom Corporation + +This license applies to all underlying Broadcom proprietary code and all +changes thereto committed to the AOSP on or before the +commit eec15a2576fe8c6abf986996d6be20ae5b6afcfe ("Proprietary Files"). + +In addition, this license applies to all Broadcom proprietary code that is NOT +governed by the Apache License, Version 2.0, unless you originally licensed +such Broadcom proprietary code under a license from Broadcom ("Broadcom SLA"). +If you have a Broadcom SLA, the terms and conditions of such SLA will continue +to govern your use of the Broadcom proprietary code, including without +limitation, the Proprietary Files. + +These Proprietary Files are the proprietary software of Broadcom Corporation +and/or its licensors, and may only be duplicated or distributed (through +multiple tiers) for internal evaluation purposes ("Authorized License"). Any +commercial redistribution of the Proprietary Files is strictly prohibited. + +Except as set forth in this Authorized License, Broadcom grants no license +(express or implied), right to use, or waiver of any kind with respect to the +Authorized Files, and Broadcom expressly reserves all rights in and to the +Authorized Files and all intellectual property rights therein. + +Except as expressly set forth in the Authorized License, + +1. These Proprietary Files, including its structure, sequence and organization, + constitutes the valuable trade secrets of Broadcom, and you shall use all + reasonable efforts to protect the confidentiality thereof, and to use this + information only for internal evaluation purposes. + +2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THESE PROPRIETARY FILES ARE PROVIDED + "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS + OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH + RESPECT TO THE PROPRIETARY FILES. BROADCOM SPECIFICALLY DISCLAIMS ANY AND + ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS + FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET + ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE + ENTIRE RISK ARISING OUT OF YOUR USE OF THE PROPRIETARY FILES UNDER THE + AUTHORIZED LICENSE. IF YOU VIOLATE THE AUTHORIZED LICENSE, THIS LICENSE WILL + BE IMMEDIATELY RESCINDED AND TERMINATED. + +3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS + LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR + EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR + USE OF OR INABILITY TO USE THE PROPRIETARY FILES EVEN IF BROADCOM HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF + THE AMOUNT ACTUALLY PAID FOR THE PROPRIETARY FILES ITSELF OR U.S. $1, + WHICHEVER IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY + FAILURE OF ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. -- cgit v1.1 From 46974c09ec89cea00242bb94fe8a3a356b239c18 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 20 Sep 2012 19:39:50 -0700 Subject: Don't print error for resetting SE route. Bug: 7113095 Change-Id: Iaa2e2b05244ec10392c98aa5dd0d5ee84e62e39f --- nci/jni/SecureElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index ff84bcc..b67ee66 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -1924,7 +1924,7 @@ bool SecureElement::routeToDefault () if (mCurrentRouteSelection == DefaultRoute) { - ALOGE ("%s: already default route", fn); + ALOGD ("%s: already default route", fn); return true; } -- cgit v1.1 From 04b8291cd90635741c1a93cd19024cf07fe0dca8 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 20 Sep 2012 20:42:52 -0700 Subject: Don't hold the routing wakelock longer than a minute. Until we figure out why routing gets stuck, don't hold the wakelock indefinitely. Bug: 7113095 Change-Id: If4d1ed8d8855e2b50ddae6d06e886faf0d58db6d --- src/com/android/nfc/NfcService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index e8fc9e4..ca1713d 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -1420,7 +1420,7 @@ public class NfcService extends Application implements DeviceHostListener { synchronized (this) { if (!mWatchDogCanceled) { // Trigger watch-dog - Log.e(TAG, "Watch dog triggered"); + Log.e(TAG, "--- NFC controller stuck while applying routing ---"); mDeviceHost.doAbort(); } } @@ -1840,7 +1840,11 @@ public class NfcService extends Application implements DeviceHostListener { } mScreenState = params[0].intValue(); - mRoutingWakeLock.acquire(); + // HACK: We've seen applying the routing configuration + // getting stuck. The operation should normally easily + // complete within a minute, so don't hold the wakelock + // any longer than that. + mRoutingWakeLock.acquire(60000); try { applyRouting(false); } finally { -- cgit v1.1 From 7d53d8d0c5903ec8c7da0ace4528a1ad5c2764cf Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 20 Sep 2012 20:42:52 -0700 Subject: Don't hold the routing wakelock longer than a minute. Until we figure out why routing gets stuck, don't hold the wakelock indefinitely. Bug: 7113095 Change-Id: If4d1ed8d8855e2b50ddae6d06e886faf0d58db6d --- src/com/android/nfc/NfcService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index e8fc9e4..ca1713d 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -1420,7 +1420,7 @@ public class NfcService extends Application implements DeviceHostListener { synchronized (this) { if (!mWatchDogCanceled) { // Trigger watch-dog - Log.e(TAG, "Watch dog triggered"); + Log.e(TAG, "--- NFC controller stuck while applying routing ---"); mDeviceHost.doAbort(); } } @@ -1840,7 +1840,11 @@ public class NfcService extends Application implements DeviceHostListener { } mScreenState = params[0].intValue(); - mRoutingWakeLock.acquire(); + // HACK: We've seen applying the routing configuration + // getting stuck. The operation should normally easily + // complete within a minute, so don't hold the wakelock + // any longer than that. + mRoutingWakeLock.acquire(60000); try { applyRouting(false); } finally { -- cgit v1.1 From 5b26e322575a1c32595ec77cde3542a88065b2be Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Mon, 24 Sep 2012 23:36:46 -0400 Subject: Don't try to set low-power mode if NFA_enable fails. Would otherwise cause stack hang. Bug: 7214014 Change-Id: I5a5373f389b06b873cee1c1fb694502d7ad598b3 --- nci/jni/NativeNfcManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index c3e76fa..eee8aae 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -720,7 +720,8 @@ static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o) } TheEnd: - PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + if (sIsNfaEnabled) + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); ALOGD ("%s: exit", __FUNCTION__); return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE; } -- cgit v1.1 From dc8a29dabea23ad526f767c4f6af949d626518d3 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Thu, 20 Sep 2012 11:33:16 -0400 Subject: Fix NXP PN544 controller interop with Broadcom controller When NDEF detection times out, stop polling temporarily. Let NXP PN544 controller poll and activate the NFC-DEP interface. Bug: 6986507 Change-Id: Iaa3194e4dbc4b9d2c16aaeb360a7f15dfd82c38a --- nci/jni/NativeNfcManager.cpp | 67 +++++++++++++++++-- nci/jni/NativeNfcTag.cpp | 101 ++++++++++++++++++---------- nci/jni/NfcTag.cpp | 85 ++++++++++++++++++++---- nci/jni/NfcTag.h | 49 ++++++++++++-- nci/jni/Pn544Interop.cpp | 153 +++++++++++++++++++++++++++++++++++++++++++ nci/jni/Pn544Interop.h | 64 ++++++++++++++++++ 6 files changed, 463 insertions(+), 56 deletions(-) create mode 100644 nci/jni/Pn544Interop.cpp create mode 100644 nci/jni/Pn544Interop.h diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index eee8aae..5fd3025 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "PowerSwitch.h" #include "JavaClassConstants.h" +#include "Pn544Interop.h" extern "C" { @@ -85,6 +86,7 @@ namespace android const char* gNativeNfcManagerClassName = "com/android/nfc/dhimpl/NativeNfcManager"; const char* gNativeNfcSecureElementClassName = "com/android/nfc/dhimpl/NativeNfcSecureElement"; void doStartupConfig (); + void startStopPolling (bool isStartPolling); } @@ -284,6 +286,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat case NFA_ACTIVATED_EVT: // NFC link/protocol activated ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d", __FUNCTION__, gIsSelectingRfInterface); + NfcTag::getInstance().setActivationState (); if (gIsSelectingRfInterface) { nativeNfcTag_doConnectStatus(true); @@ -294,13 +297,14 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat if (isPeerToPeer(eventData->activated)) { ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); - break; } - NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + else if (pn544InteropIsBusy() == false) + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); break; case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated ALOGD("%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __FUNCTION__, eventData->deactivated.type,gIsTagDeactivating); + NfcTag::getInstance().setDeactivationState (eventData->deactivated); if (gIsTagDeactivating || gIsSelectingRfInterface) { if (gIsTagDeactivating) @@ -333,6 +337,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat status, eventData->ndef_detect.protocol, eventData->ndef_detect.max_size, eventData->ndef_detect.cur_size, eventData->ndef_detect.flags); + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); nativeNfcTag_doCheckNdefResult(status, eventData->ndef_detect.max_size, eventData->ndef_detect.cur_size, eventData->ndef_detect.flags); @@ -768,7 +773,7 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) { ALOGD ("%s: wait for enable event", __FUNCTION__); sDiscoveryEnabled = true; - sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_START_EVT + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_ENABLED_EVT ALOGD ("%s: got enabled event", __FUNCTION__); } else @@ -811,6 +816,7 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) tNFA_STATUS status = NFA_STATUS_OK; ALOGD ("%s: enter;", __FUNCTION__); + pn544InteropAbortNow (); if (sDiscoveryEnabled == false) { ALOGD ("%s: already disabled", __FUNCTION__); @@ -827,7 +833,7 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) if (status == NFA_STATUS_OK) { sDiscoveryEnabled = false; - sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_STOP_EVT + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_DISABLED_EVT } else ALOGE ("%s: Failed to disable polling; error=0x%X", __FUNCTION__, status); @@ -995,7 +1001,7 @@ static jboolean nfcManager_doDeinitialize (JNIEnv* e, jobject o) ALOGD ("%s: enter", __FUNCTION__); sIsDisabling = true; - + pn544InteropAbortNow (); SecureElement::getInstance().finalize (); if (sIsNfaEnabled) @@ -1677,5 +1683,56 @@ bool nfcManager_isNfcActive() } +/******************************************************************************* +** +** Function: startStopPolling +** +** Description: Start or stop polling. +** isStartPolling: true to start polling; false to stop polling. +** +** Returns: None. +** +*******************************************************************************/ +void startStopPolling (bool isStartPolling) +{ + ALOGD ("%s: enter; isStart=%u", __FUNCTION__, isStartPolling); + tNFA_STATUS stat = NFA_STATUS_FAILED; + + startRfDiscovery (false); + if (isStartPolling) + { + tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK; + unsigned long num = 0; + if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num))) + tech_mask = num; + + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + ALOGD ("%s: enable polling", __FUNCTION__); + stat = NFA_EnablePolling (tech_mask); + if (stat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for enable event", __FUNCTION__); + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_ENABLED_EVT + } + else + ALOGE ("%s: fail enable polling; error=0x%X", __FUNCTION__, stat); + } + else + { + SyncEventGuard guard (sNfaEnableDisablePollingEvent); + ALOGD ("%s: disable polling", __FUNCTION__); + stat = NFA_DisablePolling (); + if (stat == NFA_STATUS_OK) + { + sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_DISABLED_EVT + } + else + ALOGE ("%s: fail disable polling; error=0x%X", __FUNCTION__, stat); + } + startRfDiscovery (true); + ALOGD ("%s: exit", __FUNCTION__); +} + + } /* namespace android */ diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index e7352c5..8c0426b 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -25,6 +25,7 @@ #include "Mutex.h" #include "IntervalTimer.h" #include "JavaClassConstants.h" +#include "Pn544Interop.h" extern "C" { @@ -488,18 +489,28 @@ static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle) int i = targetHandle; struct nfc_jni_native_data *nat = getNative (0, 0); NfcTag& natTag = NfcTag::getInstance (); - sNeedToSwitchRf = false; + int retCode = NFCSTATUS_SUCCESS; + sNeedToSwitchRf = false; if (i >= NfcTag::MAX_NUM_TECHNOLOGY) { ALOGE ("%s: Handle not found", __FUNCTION__); - return NFCSTATUS_FAILED; + retCode = NFCSTATUS_FAILED; + goto TheEnd; + } + + if (natTag.getActivationState() != NfcTag::Active) + { + ALOGE ("%s: tag already deactivated", __FUNCTION__); + retCode = NFCSTATUS_FAILED; + goto TheEnd; } if (natTag.mTechLibNfcTypes[i] != NFC_PROTOCOL_ISO_DEP) { ALOGD ("%s() Nfc type = %d, do nothing for non ISO_DEP", __FUNCTION__, natTag.mTechLibNfcTypes[i]); - return NFCSTATUS_SUCCESS; + retCode = NFCSTATUS_SUCCESS; + goto TheEnd; } if (natTag.mTechList[i] == TARGET_TYPE_ISO14443_3A || natTag.mTechList[i] == TARGET_TYPE_ISO14443_3B) @@ -514,7 +525,9 @@ static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle) return (switchRfInterface (NFA_INTERFACE_ISO_DEP) ? NFCSTATUS_SUCCESS : NFCSTATUS_FAILED); } - return NFCSTATUS_SUCCESS; +TheEnd: + ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode); + return retCode; } /******************************************************************************* @@ -530,22 +543,30 @@ static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle) *******************************************************************************/ static int reSelect (tNFA_INTF_TYPE rfInterface) { - ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface); + ALOGD ("%s: enter; rf intf = %d", __FUNCTION__, rfInterface); NfcTag& natTag = NfcTag::getInstance (); - ALOGD ("%s: NFA_Deactivate()", __FUNCTION__); tNFA_STATUS status; int rVal = 1; do { + //if tag has shutdown, abort this method + if (NfcTag::getInstance ().isNdefDetectionTimedOut()) + { + ALOGD ("%s: ndef detection timeout; break", __FUNCTION__); + rVal = STATUS_CODE_TARGET_LOST; + break; + } + { SyncEventGuard g (sReconnectEvent); gIsTagDeactivating = true; sGotDeactivate = false; - if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) + ALOGD ("%s: deactivate to sleep", __FUNCTION__); + if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) //deactivate to sleep state { - ALOGE ("%s: NFA_Deactivate failed, status = %d", __FUNCTION__, status); + ALOGE ("%s: deactivate failed, status = %d", __FUNCTION__, status); break; } @@ -555,8 +576,9 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) } } - if (! NfcTag::getInstance ().isActivated ()) + if (NfcTag::getInstance ().getActivationState () != NfcTag::Sleep) { + ALOGD ("%s: tag is not in sleep", __FUNCTION__); rVal = STATUS_CODE_TARGET_LOST; break; } @@ -567,7 +589,7 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) SyncEventGuard g2 (sReconnectEvent); sConnectWaitingForComplete = JNI_TRUE; - ALOGD ("%s: NFA_Select()", __FUNCTION__); + ALOGD ("%s: select interface %u", __FUNCTION__, rfInterface); gIsSelectingRfInterface = true; if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface))) { @@ -578,15 +600,15 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) sConnectOk = false; if (sReconnectEvent.wait (1000) == false) //if timeout occured { - ALOGE ("%s: wait response timeout", __FUNCTION__); + ALOGE ("%s: timeout waiting for select", __FUNCTION__); break; } } - ALOGD("%s: done waiting on NFA_Select() sConnectOk=%d", __FUNCTION__, sConnectOk); - if (! NfcTag::getInstance ().isActivated ()) + ALOGD("%s: select completed; sConnectOk=%d", __FUNCTION__, sConnectOk); + if (NfcTag::getInstance ().getActivationState () != NfcTag::Active) { - ALOGD("%s: Tag no longer active", __FUNCTION__); + ALOGD("%s: tag is not active", __FUNCTION__); rVal = STATUS_CODE_TARGET_LOST; break; } @@ -596,6 +618,7 @@ static int reSelect (tNFA_INTF_TYPE rfInterface) sConnectWaitingForComplete = JNI_FALSE; gIsTagDeactivating = false; gIsSelectingRfInterface = false; + ALOGD ("%s: exit; status=%d", __FUNCTION__, rVal); return rVal; } @@ -650,22 +673,26 @@ static bool switchRfInterface (tNFA_INTF_TYPE rfInterface) *******************************************************************************/ static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o) { - ALOGD ("%s", __FUNCTION__); - - tNFA_INTF_TYPE intf = NFA_INTERFACE_FRAME; + ALOGD ("%s: enter", __FUNCTION__); + int retCode = NFCSTATUS_SUCCESS; NfcTag& natTag = NfcTag::getInstance (); + if (natTag.getActivationState() != NfcTag::Active) + { + ALOGE ("%s: tag already deactivated", __FUNCTION__); + retCode = NFCSTATUS_FAILED; + goto TheEnd; + } + // this is only supported for type 2 or 4 (ISO_DEP) tags if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP) - intf = NFA_INTERFACE_ISO_DEP; + retCode = reSelect(NFA_INTERFACE_ISO_DEP); else if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_T2T) - intf = NFA_INTERFACE_FRAME; - else - { - return 0; // success - } + retCode = reSelect(NFA_INTERFACE_FRAME); - return reSelect(intf); +TheEnd: + ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode); + return retCode; } @@ -707,9 +734,9 @@ static jboolean nativeNfcTag_doDisconnect (JNIEnv *e, jobject o) gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT; - if (NfcTag::getInstance ().isActivated () == false) + if (NfcTag::getInstance ().getActivationState () != NfcTag::Active) { - ALOGD ("%s: tag already deactivated", __FUNCTION__); + ALOGE ("%s: tag already deactivated", __FUNCTION__); goto TheEnd; } @@ -783,7 +810,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da uint32_t bufLen = 0; jint *targetLost = NULL; - if (! NfcTag::getInstance ().isActivated ()) + if (NfcTag::getInstance ().getActivationState () != NfcTag::Active) { if (statusTargetLost) { @@ -844,7 +871,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da break; } - if (! NfcTag::getInstance ().isActivated ()) + if (NfcTag::getInstance ().getActivationState () != NfcTag::Active) { ALOGE ("%s: already deactivated", __FUNCTION__); if (targetLost) @@ -1036,7 +1063,7 @@ void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint3 ** o: Java object. ** ndefInfo: NDEF info. ** -** Returns: Status code. +** Returns: Status code; 0 is success. ** *******************************************************************************/ static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo) @@ -1053,9 +1080,9 @@ static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo) return JNI_FALSE; } - if (NfcTag::getInstance ().isActivated () == false) + if (NfcTag::getInstance ().getActivationState () != NfcTag::Active) { - ALOGE ("%s: tag not present", __FUNCTION__); + ALOGE ("%s: tag already deactivated", __FUNCTION__); goto TheEnd; } @@ -1065,7 +1092,7 @@ static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo) if (status != NFA_STATUS_OK) { - ALOGE ("%s: NFA_RwDetectNDef failed, status = %d", __FUNCTION__, status); + ALOGE ("%s: NFA_RwDetectNDef failed, status = 0x%X", __FUNCTION__, status); goto TheEnd; } @@ -1106,9 +1133,15 @@ static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo) e->ReleaseIntArrayElements (ndefInfo, ndef, 0); status = NFA_STATUS_FAILED; } + else if (sCheckNdefStatus == NFA_STATUS_TIMEOUT) + { + pn544InteropStopPolling (); + status = sCheckNdefStatus; + } else { ALOGD ("%s: unknown status 0x%X", __FUNCTION__, sCheckNdefStatus); + status = sCheckNdefStatus; } TheEnd: @@ -1118,7 +1151,7 @@ TheEnd: ALOGE ("%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno); } sCheckNdefWaitingForComplete = JNI_FALSE; - ALOGD ("%s: exit; status=%u", __FUNCTION__, status); + ALOGD ("%s: exit; status=0x%X", __FUNCTION__, status); return status; } @@ -1183,7 +1216,7 @@ static jboolean nativeNfcTag_doPresenceCheck (JNIEnv *e, jobject o) return JNI_FALSE; } - if (NfcTag::getInstance ().isActivated () == false) + if (NfcTag::getInstance ().getActivationState () != NfcTag::Active) { ALOGD ("%s: tag already deactivated", __FUNCTION__); return JNI_FALSE; diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp index e996fdd..b94355f 100755 --- a/nci/jni/NfcTag.cpp +++ b/nci/jni/NfcTag.cpp @@ -37,17 +37,18 @@ extern "C" *******************************************************************************/ NfcTag::NfcTag () : mNativeData (NULL), - mIsActivated (false), + mActivationState (Idle), mProtocol(NFC_PROTOCOL_UNKNOWN), mNumTechList (0), mtT1tMaxMessageSize (0), - mReadCompletedStatus (NFA_STATUS_OK) + mReadCompletedStatus (NFA_STATUS_OK), + mLastKovioUidLen (0), + mNdefDetectionTimedOut (false) { memset (mTechList, 0, sizeof(mTechList)); memset (mTechHandles, 0, sizeof(mTechHandles)); memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes)); memset (mTechParams, 0, sizeof(mTechParams)); - mLastKovioUidLen = 0; memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN); } @@ -81,7 +82,7 @@ NfcTag& NfcTag::getInstance () void NfcTag::initialize (nfc_jni_native_data* native) { mNativeData = native; - mIsActivated = false; + mActivationState = Idle; mProtocol = NFC_PROTOCOL_UNKNOWN; mNumTechList = 0; mtT1tMaxMessageSize = 0; @@ -108,16 +109,55 @@ void NfcTag::abort () /******************************************************************************* ** -** Function: isActivated +** Function: getActivationState ** -** Description: Is tag activated? +** Description: What is the current state: Idle, Sleep, or Activated. ** -** Returns: True if tag is activated. +** Returns: Idle, Sleep, or Activated. ** *******************************************************************************/ -bool NfcTag::isActivated () +NfcTag::ActivationState NfcTag::getActivationState () { - return mIsActivated; + return mActivationState; +} + + +/******************************************************************************* +** +** Function: setDeactivationState +** +** Description: Set the current state: Idle or Sleep. +** deactivated: state of deactivation. +** +** Returns: None. +** +*******************************************************************************/ +void NfcTag::setDeactivationState (tNFA_DEACTIVATED& deactivated) +{ + static const char fn [] = "NfcTag::setDeactivationState"; + mActivationState = Idle; + mNdefDetectionTimedOut = false; + if (deactivated.type == NFA_DEACTIVATE_TYPE_SLEEP) + mActivationState = Sleep; + ALOGD ("%s: state=%u", fn, mActivationState); +} + + +/******************************************************************************* +** +** Function: setActivationState +** +** Description: Set the current state to Active. +** +** Returns: None. +** +*******************************************************************************/ +void NfcTag::setActivationState () +{ + static const char fn [] = "NfcTag::setActivationState"; + mNdefDetectionTimedOut = false; + mActivationState = Active; + ALOGD ("%s: state=%u", fn, mActivationState); } @@ -1204,6 +1244,21 @@ bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen) /******************************************************************************* ** +** Function: isNdefDetectionTimedOut +** +** Description: Whether NDEF-detection algorithm timed out. +** +** Returns: True if NDEF-detection algorithm timed out. +** +*******************************************************************************/ +bool NfcTag::isNdefDetectionTimedOut () +{ + return mNdefDetectionTimedOut; +} + + +/******************************************************************************* +** ** Function: connectionEventHandler ** ** Description: Handle connection-related events. @@ -1215,6 +1270,8 @@ bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen) *******************************************************************************/ void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) { + static const char fn [] = "NfcTag::connectionEventHandler"; + switch (event) { case NFA_DISC_RESULT_EVT: @@ -1236,7 +1293,6 @@ void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) tNFA_ACTIVATED& activated = data->activated; if (IsSameKovio(activated)) break; - mIsActivated = true; mProtocol = activated.activate_ntf.protocol; calculateT1tMaxMessageSize (activated); discoverTechnologies (activated); @@ -1245,7 +1301,6 @@ void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) break; case NFA_DEACTIVATED_EVT: - mIsActivated = false; mProtocol = NFC_PROTOCOL_UNKNOWN; resetTechnologies (); break; @@ -1257,6 +1312,14 @@ void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data) mReadCompleteEvent.notifyOne (); } break; + + case NFA_NDEF_DETECT_EVT: + { + tNFA_NDEF_DETECT& ndef_detect = data->ndef_detect; + mNdefDetectionTimedOut = ndef_detect.status == NFA_STATUS_TIMEOUT; + if (mNdefDetectionTimedOut) + ALOGE ("%s: NDEF detection timed out", fn); + } } } diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h index 76a6bb7..7fa56ee 100755 --- a/nci/jni/NfcTag.h +++ b/nci/jni/NfcTag.h @@ -30,6 +30,7 @@ extern "C" class NfcTag { public: + enum ActivationState {Idle, Sleep, Active}; static const int MAX_NUM_TECHNOLOGY = 10; //max number of technologies supported by one or more tags int mTechList [MAX_NUM_TECHNOLOGY]; //array of NFC technologies according to NFC service int mTechHandles [MAX_NUM_TECHNOLOGY]; //array of tag handles according to NFC service @@ -100,18 +101,42 @@ public: /******************************************************************************* ** - ** Function: isActivated + ** Function: getActivationState ** - ** Description: Is tag activated? + ** Description: What is the current state: Idle, Sleep, or Activated. ** - ** Returns: True if tag is activated. + ** Returns: Idle, Sleep, or Activated. ** *******************************************************************************/ - bool isActivated (); + ActivationState getActivationState (); /******************************************************************************* ** + ** Function: setDeactivationState + ** + ** Description: Set the current state: Idle or Sleep. + ** deactivated: state of deactivation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void setDeactivationState (tNFA_DEACTIVATED& deactivated); + + + /******************************************************************************* + ** + ** Function: setActivationState + ** + ** Description: Set the current state to Active. + ** + ** Returns: None. + ** + *******************************************************************************/ + void setActivationState (); + + /******************************************************************************* + ** ** Function: getProtocol ** ** Description: Get the protocol of the current tag. @@ -197,15 +222,27 @@ public: *******************************************************************************/ bool isT2tNackResponse (const UINT8* response, UINT32 responseLen); + /******************************************************************************* + ** + ** Function: isNdefDetectionTimedOut + ** + ** Description: Whether NDEF-detection algorithm has timed out. + ** + ** Returns: True if NDEF-detection algorithm timed out. + ** + *******************************************************************************/ + bool isNdefDetectionTimedOut (); + private: nfc_jni_native_data* mNativeData; - bool mIsActivated; + ActivationState mActivationState; tNFC_PROTOCOL mProtocol; int mtT1tMaxMessageSize; //T1T max NDEF message size tNFA_STATUS mReadCompletedStatus; + int mLastKovioUidLen; // len of uid of last Kovio tag activated + bool mNdefDetectionTimedOut; // whether NDEF detection algorithm timed out tNFC_RF_TECH_PARAMS mTechParams [MAX_NUM_TECHNOLOGY]; //array of technology parameters SyncEvent mReadCompleteEvent; - int mLastKovioUidLen; // len of uid of last Kovio tag activated struct timespec mLastKovioTime; // time of last Kovio tag activation UINT8 mLastKovioUid[NFC_KOVIO_MAX_LEN]; // uid of last Kovio tag activated diff --git a/nci/jni/Pn544Interop.cpp b/nci/jni/Pn544Interop.cpp new file mode 100644 index 0000000..be92c75 --- /dev/null +++ b/nci/jni/Pn544Interop.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** +** +** Name: Pn544Interop.cpp +** +** Description: Implement operations that provide compatibility with NXP +** PN544 controller. Specifically facilitate peer-to-peer +** operations with PN544 controller. +** +*****************************************************************************/ +#include "OverrideLog.h" +#include "Pn544Interop.h" +#include "IntervalTimer.h" +#include "Mutex.h" +#include "NfcTag.h" +namespace android +{ + extern void startStopPolling (bool isStartPolling); +} + + +/***************************************************************************** +** +** private variables and functions +** +*****************************************************************************/ + + +static const int gIntervalTime = 1000; //millisecond between the check to restore polling +static IntervalTimer gTimer; +static Mutex gMutex; +static void pn544InteropStartPolling (union sigval); //callback function for interval timer +static bool gIsBusy = false; //is timer busy? +static bool gAbortNow = false; //stop timer during next callback + + +/******************************************************************************* +** +** Function: pn544InteropStopPolling +** +** Description: Stop polling to let NXP PN544 controller poll. +** PN544 should activate in P2P mode. +** +** Returns: None +** +*******************************************************************************/ +void pn544InteropStopPolling () +{ + ALOGD ("%s: enter", __FUNCTION__); + gMutex.lock (); + gTimer.kill (); + android::startStopPolling (false); + gIsBusy = true; + gAbortNow = false; + gTimer.set (gIntervalTime, pn544InteropStartPolling); //after some time, start polling again + gMutex.unlock (); + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: pn544InteropStartPolling +** +** Description: Start polling when activation state is idle. +** sigval: Unused. +** +** Returns: None +** +*******************************************************************************/ +void pn544InteropStartPolling (union sigval) +{ + ALOGD ("%s: enter", __FUNCTION__); + gMutex.lock (); + NfcTag::ActivationState state = NfcTag::getInstance ().getActivationState (); + + if (gAbortNow) + { + ALOGD ("%s: abort now", __FUNCTION__); + gIsBusy = false; + goto TheEnd; + } + + if (state == NfcTag::Idle) + { + ALOGD ("%s: start polling", __FUNCTION__); + android::startStopPolling (true); + gIsBusy = false; + } + else + { + ALOGD ("%s: try again later", __FUNCTION__); + gTimer.set (gIntervalTime, pn544InteropStartPolling); //after some time, start polling again + } + +TheEnd: + gMutex.unlock (); + ALOGD ("%s: exit", __FUNCTION__); +} + + +/******************************************************************************* +** +** Function: pn544InteropIsBusy +** +** Description: Is the code performing operations? +** +** Returns: True if the code is busy. +** +*******************************************************************************/ +bool pn544InteropIsBusy () +{ + bool isBusy = false; + gMutex.lock (); + isBusy = gIsBusy; + gMutex.unlock (); + ALOGD ("%s: %u", __FUNCTION__, isBusy); + return isBusy; +} + + +/******************************************************************************* +** +** Function: pn544InteropAbortNow +** +** Description: Request to abort all operations. +** +** Returns: None. +** +*******************************************************************************/ +void pn544InteropAbortNow () +{ + ALOGD ("%s", __FUNCTION__); + gMutex.lock (); + gAbortNow = true; + gMutex.unlock (); +} + diff --git a/nci/jni/Pn544Interop.h b/nci/jni/Pn544Interop.h new file mode 100644 index 0000000..c9a2df6 --- /dev/null +++ b/nci/jni/Pn544Interop.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** +** +** Name: Pn544Interop.h +** +** Description: Implement operations that provide compatibility with NXP +** PN544 controller. Specifically facilitate peer-to-peer +** operations with PN544 controller. +** +*****************************************************************************/ +#pragma once +#include "NfcJniUtil.h" + + +/******************************************************************************* +** +** Function: pn544InteropStopPolling +** +** Description: Stop polling to let NXP PN544 controller poll. +** PN544 should activate in P2P mode. +** +** Returns: None +** +*******************************************************************************/ +void pn544InteropStopPolling (); + + +/******************************************************************************* +** +** Function: pn544InteropIsBusy +** +** Description: Is the code performing operations? +** +** Returns: True if the code is busy. +** +*******************************************************************************/ +bool pn544InteropIsBusy (); + + +/******************************************************************************* +** +** Function: pn544InteropAbortNow +** +** Description: Request to abort all operations. +** +** Returns: None. +** +*******************************************************************************/ +void pn544InteropAbortNow (); -- cgit v1.1 From 2f9909a2ac0786983f3f564364053c56ef353819 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Tue, 25 Sep 2012 18:45:46 -0400 Subject: Tell secure element to warm-reset when closing pipe to DH. Set HCI registry to cause Oberthur secure element to perform warm-reset. We use this to close any applets that the DH may have opened during communication to the SE. This feature is Oberthur-specific. Bug: 7163680 Change-Id: Id0589b5b41bbea1df9b8dbd73abd5a112f773916 --- nci/jni/SecureElement.cpp | 34 +++++++++++++++++++++++++++++++++- nci/jni/SecureElement.h | 3 +++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index b67ee66..2f94047 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -70,7 +70,9 @@ SecureElement::SecureElement () mCommandStatus (NFA_STATUS_OK), mIsPiping (false), mCurrentRouteSelection (NoRoute), - mActualResponseSize(0) + mActualResponseSize(0), + mUseOberthurWarmReset (false), + mOberthurWarmResetCommand (3) { memset (&mEeInfo, 0, sizeof(mEeInfo)); memset (&mUiccInfo, 0, sizeof(mUiccInfo)); @@ -153,6 +155,12 @@ bool SecureElement::initialize (nfc_jni_native_data* native) mActiveSeOverride = num; ALOGD ("%s: Active SE override: %d", fn, mActiveSeOverride); + if (GetNumValue("OBERTHUR_WARM_RESET_COMMAND", &num, sizeof(num))) + { + mUseOberthurWarmReset = true; + mOberthurWarmResetCommand = (UINT8) num; + } + mActiveEeHandle = NFA_HANDLE_INVALID; mNfaHciHandle = NFA_HANDLE_INVALID; @@ -777,6 +785,21 @@ bool SecureElement::disconnectEE (jint seID) ALOGD("%s: seID=0x%X; handle=0x%04x", fn, seID, eeHandle); + if (mUseOberthurWarmReset) + { + //send warm-reset command to Oberthur secure element which deselects the applet; + //this is an Oberthur-specific command; + ALOGD("%s: try warm-reset on pipe id 0x%X; cmd=0x%X", fn, mNewPipeId, mOberthurWarmResetCommand); + SyncEventGuard guard (mRegistryEvent); + nfaStat = NFA_HciSetRegistry (mNfaHciHandle, mNewPipeId, + 1, 1, &mOberthurWarmResetCommand); + if (nfaStat == NFA_STATUS_OK) + { + mRegistryEvent.wait (); + ALOGD("%s: completed warm-reset on pipe 0x%X", fn, mNewPipeId); + } + } + if (mNewSourceGate) { SyncEventGuard guard (mDeallocateGateEvent); @@ -1718,6 +1741,15 @@ void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* event } break; + case NFA_HCI_SET_REG_RSP_EVT: //received response to write registry command + { + tNFA_HCI_REGISTRY& registry = eventData->registry; + ALOGD ("%s: NFA_HCI_SET_REG_RSP_EVT; status=0x%X; pipe=0x%X", fn, registry.status, registry.pipe); + SyncEventGuard guard (sSecElem.mRegistryEvent); + sSecElem.mRegistryEvent.notifyOne (); + break; + } + default: ALOGE ("%s: unknown event code=0x%X ????", fn, event); break; diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index b887513..6a5cebd 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -372,6 +372,8 @@ private: bool mIsPiping; //is a pipe connected to the controller? RouteSelection mCurrentRouteSelection; int mActualResponseSize; //number of bytes in the response received from secure element + bool mUseOberthurWarmReset; //whether to use warm-reset command + UINT8 mOberthurWarmResetCommand; //warm-reset command byte tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe tNFA_EE_DISCOVER_REQ mUiccInfo; tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg; @@ -389,6 +391,7 @@ private: SyncEvent mAidAddRemoveEvent; SyncEvent mTransceiveEvent; SyncEvent mVerInfoEvent; + SyncEvent mRegistryEvent; UINT8 mVerInfo [3]; UINT8 mResponseData [MAX_RESPONSE_SIZE]; RouteDataSet mRouteDataSet; //routing data -- cgit v1.1 From a112f9c00e3337ef38ea8e1715a99db4966c7219 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 25 Sep 2012 22:27:32 -0700 Subject: Fix NFC->Bluetooth headset/a2dp connection. The new BT stack has some changed behavior with respect to getProfileProxy() - it cannot be called before BT is enabled. Moved the proxy code into BluetoothHeadsetHandover and deal with it there. Bug: 7150073 Change-Id: Ia227e0f6fa5639ed68379c751104ade82c893af6 --- .../nfc/handover/BluetoothHeadsetHandover.java | 223 ++++++++++++++------- src/com/android/nfc/handover/HandoverManager.java | 43 +--- 2 files changed, 159 insertions(+), 107 deletions(-) diff --git a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java index 7974dfa..644ecbd 100644 --- a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java +++ b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java @@ -44,9 +44,8 @@ import com.android.nfc.R; * designed to be re-used after the sequence has completed or timed out. * Subsequent NFC interactions should use new objects. * - * TODO: UI review */ -public class BluetoothHeadsetHandover { +public class BluetoothHeadsetHandover implements BluetoothProfile.ServiceListener { static final String TAG = HandoverManager.TAG; static final boolean DBG = HandoverManager.DBG; @@ -57,28 +56,33 @@ public class BluetoothHeadsetHandover { static final int STATE_INIT = 0; static final int STATE_TURNING_ON = 1; - static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 2; - static final int STATE_BONDING = 3; - static final int STATE_CONNECTING = 4; - static final int STATE_DISCONNECTING = 5; - static final int STATE_COMPLETE = 6; + static final int STATE_WAITING_FOR_PROXIES = 2; + static final int STATE_INIT_COMPLETE = 3; + static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 4; + static final int STATE_BONDING = 5; + static final int STATE_CONNECTING = 6; + static final int STATE_DISCONNECTING = 7; + static final int STATE_COMPLETE = 8; static final int RESULT_PENDING = 0; static final int RESULT_CONNECTED = 1; static final int RESULT_DISCONNECTED = 2; + static final int ACTION_INIT = 0; static final int ACTION_DISCONNECT = 1; static final int ACTION_CONNECT = 2; static final int MSG_TIMEOUT = 1; + static final int MSG_NEXT_STEP = 2; final Context mContext; final BluetoothDevice mDevice; final String mName; final HandoverPowerManager mHandoverPowerManager; - final BluetoothA2dp mA2dp; - final BluetoothHeadset mHeadset; final Callback mCallback; + final BluetoothAdapter mBluetoothAdapter; + + final Object mLock = new Object(); // only used on main thread int mAction; @@ -86,21 +90,24 @@ public class BluetoothHeadsetHandover { int mHfpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING int mA2dpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING + // protected by mLock + BluetoothA2dp mA2dp; + BluetoothHeadset mHeadset; + public interface Callback { public void onBluetoothHeadsetHandoverComplete(boolean connected); } public BluetoothHeadsetHandover(Context context, BluetoothDevice device, String name, - HandoverPowerManager powerManager, BluetoothA2dp a2dp, BluetoothHeadset headset, - Callback callback) { + HandoverPowerManager powerManager, Callback callback) { checkMainThread(); // mHandler must get get constructed on Main Thread for toasts to work mContext = context; mDevice = device; mName = name; mHandoverPowerManager = powerManager; - mA2dp = a2dp; - mHeadset = headset; mCallback = callback; + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mState = STATE_INIT; } @@ -111,6 +118,7 @@ public class BluetoothHeadsetHandover { public void start() { checkMainThread(); if (mState != STATE_INIT) return; + if (mBluetoothAdapter == null) return; IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); @@ -122,15 +130,8 @@ public class BluetoothHeadsetHandover { mContext.registerReceiver(mReceiver, filter); - if (mA2dp.getConnectedDevices().contains(mDevice) || - mHeadset.getConnectedDevices().contains(mDevice)) { - Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName); - mAction = ACTION_DISCONNECT; - } else { - Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName); - mAction = ACTION_CONNECT; - } mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS); + mAction = ACTION_INIT; nextStep(); } @@ -138,35 +139,83 @@ public class BluetoothHeadsetHandover { * Called to execute next step in state machine */ void nextStep() { - if (mAction == ACTION_CONNECT) { + if (mAction == ACTION_INIT) { + nextStepInit(); + } else if (mAction == ACTION_CONNECT) { nextStepConnect(); } else { nextStepDisconnect(); } } - void nextStepDisconnect() { + /* + * Enables bluetooth and gets the profile proxies + */ + void nextStepInit() { switch (mState) { case STATE_INIT: - mState = STATE_DISCONNECTING; - if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { - mHfpResult = RESULT_PENDING; - mHeadset.disconnect(mDevice); - } else { - mHfpResult = RESULT_DISCONNECTED; - } - if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { - mA2dpResult = RESULT_PENDING; - mA2dp.disconnect(mDevice); - } else { - mA2dpResult = RESULT_DISCONNECTED; + if (!mHandoverPowerManager.isBluetoothEnabled()) { + if (mHandoverPowerManager.enableBluetooth()) { + // Bluetooth is being enabled + mState = STATE_TURNING_ON; + } else { + toast(mContext.getString(R.string.failed_to_enable_bt)); + complete(false); + } + break; } - if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { - toast(mContext.getString(R.string.disconnecting_headset ) + " " + - mName + "..."); + // fall-through + case STATE_TURNING_ON: + if (mA2dp == null || mHeadset == null) { + mState = STATE_WAITING_FOR_PROXIES; + if (!getProfileProxys()) { + complete(false); + } break; } // fall-through + case STATE_WAITING_FOR_PROXIES: + mState = STATE_INIT_COMPLETE; + // Check connected devices and see if we need to disconnect + synchronized(mLock) { + if (mA2dp.getConnectedDevices().contains(mDevice) || + mHeadset.getConnectedDevices().contains(mDevice)) { + Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName); + mAction = ACTION_DISCONNECT; + } else { + Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName); + mAction = ACTION_CONNECT; + } + } + nextStep(); + } + + } + + void nextStepDisconnect() { + switch (mState) { + case STATE_INIT_COMPLETE: + mState = STATE_DISCONNECTING; + synchronized (mLock) { + if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { + mHfpResult = RESULT_PENDING; + mHeadset.disconnect(mDevice); + } else { + mHfpResult = RESULT_DISCONNECTED; + } + if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) { + mA2dpResult = RESULT_PENDING; + mA2dp.disconnect(mDevice); + } else { + mA2dpResult = RESULT_DISCONNECTED; + } + if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { + toast(mContext.getString(R.string.disconnecting_headset ) + " " + + mName + "..."); + break; + } + } + // fall-through case STATE_DISCONNECTING: if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { // still disconnecting @@ -178,26 +227,26 @@ public class BluetoothHeadsetHandover { complete(false); break; } + + } + + boolean getProfileProxys() { + if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET)) + return false; + + if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP)) + return false; + + return true; } void nextStepConnect() { switch (mState) { - case STATE_INIT: - if (!mHandoverPowerManager.isBluetoothEnabled()) { - if (mHandoverPowerManager.enableBluetooth()) { - // Bluetooth is being enabled - mState = STATE_TURNING_ON; - } else { - toast(mContext.getString(R.string.failed_to_enable_bt)); - complete(false); - } - break; - } - // fall-through - case STATE_TURNING_ON: + case STATE_INIT_COMPLETE: if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) { requestPairConfirmation(); mState = STATE_WAITING_FOR_BOND_CONFIRMATION; + break; } // fall-through @@ -211,21 +260,23 @@ public class BluetoothHeadsetHandover { // Bluetooth Profile service will correctly serialize // HFP then A2DP connect mState = STATE_CONNECTING; - if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { - mHfpResult = RESULT_PENDING; - mHeadset.connect(mDevice); - } else { - mHfpResult = RESULT_CONNECTED; - } - if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { - mA2dpResult = RESULT_PENDING; - mA2dp.connect(mDevice); - } else { - mA2dpResult = RESULT_CONNECTED; - } - if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { - toast(mContext.getString(R.string.connecting_headset) + " " + mName + "..."); - break; + synchronized (mLock) { + if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { + mHfpResult = RESULT_PENDING; + mHeadset.connect(mDevice); + } else { + mHfpResult = RESULT_CONNECTED; + } + if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) { + mA2dpResult = RESULT_PENDING; + mA2dp.connect(mDevice); + } else { + mA2dpResult = RESULT_CONNECTED; + } + if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) { + toast(mContext.getString(R.string.connecting_headset) + " " + mName + "..."); + break; + } } // fall-through case STATE_CONNECTING: @@ -260,7 +311,7 @@ public class BluetoothHeadsetHandover { if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action) && mState == STATE_TURNING_ON) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); if (state == BluetoothAdapter.STATE_ON) { - nextStepConnect(); + nextStep(); } else if (state == BluetoothAdapter.STATE_OFF) { toast(mContext.getString(R.string.failed_to_enable_bt)); complete(false); @@ -313,6 +364,16 @@ public class BluetoothHeadsetHandover { mState = STATE_COMPLETE; mContext.unregisterReceiver(mReceiver); mHandler.removeMessages(MSG_TIMEOUT); + synchronized (mLock) { + if (mA2dp != null) { + mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp); + } + if (mHeadset != null) { + mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadset); + } + mA2dp = null; + mHeadset = null; + } mCallback.onBluetoothHeadsetHandoverComplete(connected); } @@ -348,6 +409,9 @@ public class BluetoothHeadsetHandover { Log.i(TAG, "Timeout completing BT handover"); complete(false); break; + case MSG_NEXT_STEP: + nextStep(); + break; } } }; @@ -364,4 +428,29 @@ public class BluetoothHeadsetHandover { throw new IllegalThreadStateException("must be called on main thread"); } } + + @Override + public void onServiceConnected(int profile, BluetoothProfile proxy) { + synchronized (mLock) { + switch (profile) { + case BluetoothProfile.HEADSET: + mHeadset = (BluetoothHeadset) proxy; + if (mA2dp != null) { + mHandler.sendEmptyMessage(MSG_NEXT_STEP); + } + break; + case BluetoothProfile.A2DP: + mA2dp = (BluetoothA2dp) proxy; + if (mHeadset != null) { + mHandler.sendEmptyMessage(MSG_NEXT_STEP); + } + break; + } + } + } + + @Override + public void onServiceDisconnected(int profile) { + // We can ignore these + } } diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index 8983389..fccdd17 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -62,8 +62,7 @@ import com.android.nfc.R; /** * Manages handover of NFC to other technologies. */ -public class HandoverManager implements BluetoothProfile.ServiceListener, - BluetoothHeadsetHandover.Callback { +public class HandoverManager implements BluetoothHeadsetHandover.Callback { static final String TAG = "NfcHandover"; static final boolean DBG = true; @@ -142,8 +141,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, // Variables below synchronized on HandoverManager.this final HashMap, HandoverTransfer> mTransfers; - BluetoothHeadset mBluetoothHeadset; - BluetoothA2dp mBluetoothA2dp; BluetoothHeadsetHandover mBluetoothHeadsetHandover; boolean mBluetoothHeadsetConnected; @@ -613,10 +610,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, public HandoverManager(Context context) { mContext = context; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - if (mBluetoothAdapter != null) { - mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET); - mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP); - } mNotificationManager = (NotificationManager) mContext.getSystemService( Context.NOTIFICATION_SERVICE); @@ -793,9 +786,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, if (!handover.valid) return true; synchronized (HandoverManager.this) { - if (mBluetoothAdapter == null || - mBluetoothA2dp == null || - mBluetoothHeadset == null) { + if (mBluetoothAdapter == null) { if (DBG) Log.d(TAG, "BT handover, but BT not available"); return true; } @@ -804,7 +795,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, return true; } mBluetoothHeadsetHandover = new BluetoothHeadsetHandover(mContext, handover.device, - handover.name, mHandoverPowerManager, mBluetoothA2dp, mBluetoothHeadset, this); + handover.name, mHandoverPowerManager, this); mBluetoothHeadsetHandover.start(); } return true; @@ -984,34 +975,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener, } @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - synchronized (HandoverManager.this) { - switch (profile) { - case BluetoothProfile.HEADSET: - mBluetoothHeadset = (BluetoothHeadset) proxy; - break; - case BluetoothProfile.A2DP: - mBluetoothA2dp = (BluetoothA2dp) proxy; - break; - } - } - } - - @Override - public void onServiceDisconnected(int profile) { - synchronized (HandoverManager.this) { - switch (profile) { - case BluetoothProfile.HEADSET: - mBluetoothHeadset = null; - break; - case BluetoothProfile.A2DP: - mBluetoothA2dp = null; - break; - } - } - } - - @Override public void onBluetoothHeadsetHandoverComplete(boolean connected) { synchronized (HandoverManager.this) { mBluetoothHeadsetHandover = null; -- cgit v1.1 From 18ccd96ac38d28864230f4f1d264fd1a4cc16d8a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 26 Sep 2012 10:53:59 -0700 Subject: Enable/disable RF discovery only when needed. Fixes coming out of suspend with EE routing enabled. Bug: 7233312 Change-Id: Ibbb9d7c26c2152fbac543d84d3306fc0ed50272d --- nci/jni/NativeNfcManager.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 5fd3025..f4d5573 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -109,6 +109,7 @@ static SyncEvent sNfaSetConfigEvent; // event for Set_Config.... static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; +static bool sRfEnabled = false; // whether RF discovery is enabled #define NFA_DM_PWR_STATE_UNKNOWN (-1) // power off sleep state is unkown until is is reported back from NFA... static int sConnlessSap = 0; static int sConnlessLinkMiu = 0; @@ -766,6 +767,11 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); + if (sRfEnabled) { + // Stop RF discovery to reconfigure + startRfDiscovery(false); + } + { SyncEventGuard guard (sNfaEnableDisablePollingEvent); stat = NFA_EnablePolling (tech_mask); @@ -1159,11 +1165,12 @@ static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { ALOGD ("%s: enter", __FUNCTION__); bool stat = true; - PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); - // Stop RF Discovery. - startRfDiscovery (false); + if (sRfEnabled) { + // Stop RF Discovery if we were polling + startRfDiscovery (false); + } if (sIsSecElemSelected) { @@ -1177,7 +1184,6 @@ static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o) sIsSecElemSelected = true; TheEnd: - // Restart RF Discovery. startRfDiscovery (true); ALOGD ("%s: exit", __FUNCTION__); @@ -1581,6 +1587,7 @@ void startRfDiscovery(bool isStart) if (status == NFA_STATUS_OK) { sNfaEnableDisablePollingEvent.wait (); //wait for NFA_RF_DISCOVERY_xxxx_EVT + sRfEnabled = isStart; } else { -- cgit v1.1 From 914d6caa70f544fb3dd0710de59dff090c695caa Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 26 Sep 2012 13:09:20 -0700 Subject: Disable all RF activity when DH connects to SE. If we leave RF polling/listen enabled while talking to the SE from the DH, there is corruption on frames sent out over SWP. To resolve this, disable discovery (both poll and listen) when the SE is route to the DH. This also makes the behavior identical to that of the PN65N devices, which don't allow any RF activity when the SE is routed to the host. Bug: 7004303 Change-Id: I05ad55a6f75b9f346feaf20dccefc23919ff538f --- nci/jni/NativeNfcManager.cpp | 2 +- nci/jni/SecureElement.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index f4d5573..99ffc77 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -87,6 +87,7 @@ namespace android const char* gNativeNfcSecureElementClassName = "com/android/nfc/dhimpl/NativeNfcSecureElement"; void doStartupConfig (); void startStopPolling (bool isStartPolling); + void startRfDiscovery (bool isStart); } @@ -132,7 +133,6 @@ static UINT32 sConfigUpdated = 0; static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); static bool isPeerToPeer (tNFA_ACTIVATED& activated); -static void startRfDiscovery (bool isStart); ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 2f94047..5f370cc 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -37,6 +37,10 @@ int gSEId = -1; // secure element ID to use in connectEE(), -1 means not set int gGatePipe = -1; // gate id or static pipe id to use in connectEE(), -1 means not set bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if false, use as gate id +namespace android +{ + extern void startRfDiscovery (bool isStart); +} ////////////////////////////////////////////// ////////////////////////////////////////////// @@ -630,6 +634,9 @@ bool SecureElement::connectEE () return (false); } + // Disable RF discovery completely while the DH is connected + android::startRfDiscovery(false); + mNewSourceGate = 0; if (gGatePipe == -1) @@ -809,6 +816,11 @@ bool SecureElement::disconnectEE (jint seID) ALOGE ("%s: fail dealloc gate; error=0x%X", fn, nfaStat); } mIsPiping = false; + // Re-enable RF discovery + // Note that it only effactuates the current configuration, + // so if polling/listening were configured OFF (forex because + // the screen was off), they will stay OFF with this call. + android::startRfDiscovery(true); return true; } -- cgit v1.1 From a80bb9a5333d4f4f749778f3a7b13b8c7ae58c6f Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Fri, 28 Sep 2012 12:20:35 -0400 Subject: Do not activate a tag during NFC disable. Could cause RF field to remain on. Bug: 7164846 Change-Id: I82efc29b96c7129465fea5354fa5484da31618a6 --- nci/jni/NativeNfcManager.cpp | 10 ++++++++-- nci/jni/RouteDataSet.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 99ffc77..e65e30e 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -267,7 +267,10 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat break; case NFA_SELECT_RESULT_EVT: // NFC link/protocol discovery select response - ALOGD("%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = %d", __FUNCTION__, eventData->status, gIsSelectingRfInterface); + ALOGD("%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = %d, sIsDisabling=%d", __FUNCTION__, eventData->status, gIsSelectingRfInterface, sIsDisabling); + + if (sIsDisabling) + break; if (eventData->status != NFA_STATUS_OK) { @@ -286,7 +289,10 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat break; case NFA_ACTIVATED_EVT: // NFC link/protocol activated - ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d", __FUNCTION__, gIsSelectingRfInterface); + ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d, sIsDisabling=%d", __FUNCTION__, gIsSelectingRfInterface, sIsDisabling); + if (sIsDisabling) + break; + NfcTag::getInstance().setActivationState (); if (gIsSelectingRfInterface) { diff --git a/nci/jni/RouteDataSet.h b/nci/jni/RouteDataSet.h index d937dec..d2a09b8 100644 --- a/nci/jni/RouteDataSet.h +++ b/nci/jni/RouteDataSet.h @@ -152,7 +152,7 @@ private: ** Name: RouteDataSet ** ** Description: Import and export general routing data using a XML file. -** See /data/bcmnfc/param/route.xml +** See /data/bcm/param/route.xml ** *****************************************************************************/ class RouteDataSet -- cgit v1.1 From 43727fbb7cc3b799a46c3d6ddeff24dd83081449 Mon Sep 17 00:00:00 2001 From: Paul Chaisson Date: Sun, 30 Sep 2012 09:50:36 -0400 Subject: Power up the NFCC when DH wants to talk to the SE. We need to allow usecases were the DH wants to talk to the SE even if the screen is off. Bug: 7257431 Change-Id: Iad66ef29757985b7aab5f0748fbf7589b3777bc3 --- nci/jni/NativeNfcManager.cpp | 34 ++++++------------ nci/jni/NativeSecureElement.cpp | 16 +++++++++ nci/jni/PowerSwitch.cpp | 32 ++++++++++------- nci/jni/PowerSwitch.h | 42 ++++++++++++++-------- .../com/android/nfc/dhimpl/NativeNfcManager.java | 2 -- 5 files changed, 73 insertions(+), 53 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index e65e30e..4ff03f7 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -808,6 +808,8 @@ static void nfcManager_enableDiscovery (JNIEnv* e, jobject o) // Actually start discovery. startRfDiscovery (true); + PowerSwitch::getInstance ().setModeOn (PowerSwitch::DISCOVERY); + ALOGD ("%s: exit", __FUNCTION__); } @@ -853,7 +855,8 @@ void nfcManager_disableDiscovery (JNIEnv* e, jobject o) PeerToPeer::getInstance().enableP2pListening (false); - if (!sIsSecElemSelected) + //if nothing is active after this, then tell the controller to power down + if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::DISCOVERY)) PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); TheEnd: @@ -1171,6 +1174,7 @@ static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { ALOGD ("%s: enter", __FUNCTION__); bool stat = true; + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); if (sRfEnabled) { @@ -1192,6 +1196,8 @@ static void nfcManager_doSelectSecureElement(JNIEnv *e, jobject o) TheEnd: startRfDiscovery (true); + PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_ROUTING); + ALOGD ("%s: exit", __FUNCTION__); } @@ -1234,10 +1240,10 @@ static void nfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) SecureElement::getInstance().deactivate (0xABCDEF); TheEnd: - //if power level was changed at the top of this method, - //then restore to low power - if (!sDiscoveryEnabled) + //if nothing is active after this, then tell the controller to power down + if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_ROUTING)) PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + ALOGD ("%s: exit", __FUNCTION__); } @@ -1459,23 +1465,6 @@ static void nfcManager_doSetP2pTargetModes (JNIEnv *e, jobject o, jint modes) //this function is not called by the NFC service nor exposed by public API. } -/******************************************************************************* -** -** Function nfcManager_doSetScreenState -** -** Description Forward the Screen On/Off state to native code for enhanced -** power saving mode. -** -** Returns true -** -*******************************************************************************/ -jboolean nfcManager_doSetScreenState(JNIEnv *e, jobject o, jboolean screenState) -{ - ALOGD ("%s(%d)", __FUNCTION__, screenState); - PowerSwitch::getInstance().setScreenState(screenState == JNI_TRUE); - return JNI_TRUE; -} - /***************************************************************************** ** ** JNI functions for android-4.0.1_r1 @@ -1548,9 +1537,6 @@ static JNINativeMethod gMethods[] = {"doDump", "()Ljava/lang/String;", (void *)nfcManager_doDump}, - - {"doSetScreenState", "(Z)Z", - (void *)nfcManager_doSetScreenState}, }; diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp index 8379162..104d4ea 100755 --- a/nci/jni/NativeSecureElement.cpp +++ b/nci/jni/NativeSecureElement.cpp @@ -16,6 +16,7 @@ #include "OverrideLog.h" #include "SecureElement.h" #include "JavaClassConstants.h" +#include "PowerSwitch.h" namespace android @@ -44,6 +45,10 @@ static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, job bool stat = true; jint secElemHandle = 0; + //tell the controller to power up to get ready for sec elem operations + PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); + PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_CONNECTED); + //if controller is not routing AND there is no pipe connected, //then turn on the sec elem if (! SecureElement::getInstance().isBusy()) @@ -59,6 +64,13 @@ static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, job SecureElement::getInstance().deactivate (0); } + //if code fails to connect to the secure element, and nothing is active, then + //tell the controller to power down + if ((!stat) && (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_CONNECTED))) + { + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + } + TheEnd: ALOGD("%s: exit; return handle=0x%X", __FUNCTION__, secElemHandle); return secElemHandle; @@ -89,6 +101,10 @@ static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIE if (! SecureElement::getInstance().isBusy()) SecureElement::getInstance().deactivate (handle); + //if nothing is active after this, then tell the controller to power down + if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_CONNECTED)) + PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER); + ALOGD("%s: exit", __FUNCTION__); return stat ? JNI_TRUE : JNI_FALSE; } diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp index 6c1df71..f3fd316 100755 --- a/nci/jni/PowerSwitch.cpp +++ b/nci/jni/PowerSwitch.cpp @@ -31,6 +31,9 @@ namespace android PowerSwitch PowerSwitch::sPowerSwitch; +const PowerSwitch::PowerActivity PowerSwitch::DISCOVERY=0x01; +const PowerSwitch::PowerActivity PowerSwitch::SE_ROUTING=0x02; +const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED=0x04; /******************************************************************************* ** @@ -43,7 +46,7 @@ PowerSwitch PowerSwitch::sPowerSwitch; *******************************************************************************/ PowerSwitch::PowerSwitch () : mCurrLevel (UNKNOWN_LEVEL), - mScreenState (true), + mCurrActivity(0), mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN), mDesiredScreenOffPowerState (0) { @@ -176,35 +179,38 @@ bool PowerSwitch::setLevel (PowerLevel newLevel) /******************************************************************************* ** -** Function: isScreenOn +** Function: setModeOff ** -** Description: Get the current platform power level. +** Description: Set a mode to be deactive. ** -** Returns: true if screen is on (locked or unlocked). +** Returns: True if any mode is still active. ** *******************************************************************************/ -bool PowerSwitch::isScreenOn () +bool PowerSwitch::setModeOff (PowerActivity deactivated) { - return mScreenState; + mCurrActivity &= ~deactivated; + ALOGD ("PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x", deactivated, mCurrActivity); + return (mCurrActivity != 0); } /******************************************************************************* ** -** Function: setScreenState +** Function: setModeOn ** -** Description: Set the Platform's screen state -** state: true for screen on, flase for screem off +** Description: Set a mode to be active. ** -** Returns: True if ok. +** Returns: True if any mode is active. ** *******************************************************************************/ -bool PowerSwitch::setScreenState(bool state) +bool PowerSwitch::setModeOn (PowerActivity activated) { - mScreenState = state; - return true; + mCurrActivity |= activated; + ALOGD ("PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated, mCurrActivity); + return (mCurrActivity != 0); } + /******************************************************************************* ** ** Function: setPowerOffSleepState diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h index 5c939ee..28362ba 100755 --- a/nci/jni/PowerSwitch.h +++ b/nci/jni/PowerSwitch.h @@ -45,6 +45,18 @@ public: /******************************************************************************* ** + ** Description: DISCOVERY: Discovery is enabled + ** SE_ROUTING: Routing to SE is enabled. + ** SE_CONNECTED: SE is connected. + ** + *******************************************************************************/ + typedef int PowerActivity; + static const PowerActivity DISCOVERY; + static const PowerActivity SE_ROUTING; + static const PowerActivity SE_CONNECTED; + + /******************************************************************************* + ** ** Description: Platform Power Level, copied from NativeNfcBrcmPowerMode.java. ** UNKNOWN_LEVEL: power level is unknown. ** POWER_OFF: The phone is turned OFF @@ -123,39 +135,40 @@ public: /******************************************************************************* ** - ** Function: isScreenOn + ** Function: setLevel ** - ** Description: Get the current screen state of the platform host. + ** Description: Set the controller's power level. + ** level: power level. ** - ** Returns: true if screen if on, (locked or unlocked). + ** Returns: True if ok. ** *******************************************************************************/ - bool isScreenOn (); + bool setLevel (PowerLevel level); /******************************************************************************* ** - ** Function: setLevel + ** Function: setModeOff ** - ** Description: Set the controller's power level. - ** level: power level. + ** Description: Set a mode to be deactive. ** - ** Returns: True if ok. + ** Returns: True if any mode is still active. ** *******************************************************************************/ - bool setLevel (PowerLevel level); + bool setModeOff (PowerActivity deactivated); + /******************************************************************************* ** - ** Function: setScreenState + ** Function: setModeOn ** - ** Description: Set the Platform's screen state - ** state: true for screen on, flase for screem off + ** Description: Set a mode to be active. ** - ** Returns: True if ok. + ** Returns: True if any mode is active. ** *******************************************************************************/ - bool setScreenState (bool state); + bool setModeOn (PowerActivity activated); + /******************************************************************************* ** @@ -202,6 +215,7 @@ private: static PowerSwitch sPowerSwitch; //singleton object static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown SyncEvent mPowerStateEvent; + PowerActivity mCurrActivity; /******************************************************************************* diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index 8e53ad1..921e266 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -57,8 +57,6 @@ public class NativeNfcManager implements DeviceHost { mContext = context; } - public static native boolean doSetScreenState(boolean state); - public native boolean initializeNativeStructure(); private native boolean doDownload(); -- cgit v1.1 From e8f4eba219835c4c46af6be49a25f96679aea864 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 1 Oct 2012 12:13:56 -0700 Subject: Fix native crash during RF field notifications. Bug: 7264008 Change-Id: I2647b0c6adf8f95e21d9f789c411742aef19c5ad --- nci/jni/NativeNfcManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 99ffc77..62d62a9 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -565,7 +565,7 @@ void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData) ALOGD ("%s: NFA_DM_RF_FIELD_EVT; status=0x%X; field status=%u", __FUNCTION__, eventData->rf_field.status, eventData->rf_field.rf_field_status); - if (eventData->rf_field.status == NFA_STATUS_OK) + if (!sIsDisabling && eventData->rf_field.status == NFA_STATUS_OK) SecureElement::getInstance().notifyRfFieldEvent (eventData->rf_field.rf_field_status == NFA_DM_RF_FIELD_ON); break; -- cgit v1.1 From e897cc402e50a06ccd08b03c8942a2f17e46daef Mon Sep 17 00:00:00 2001 From: Paul Chaisson Date: Sun, 30 Sep 2012 21:42:11 -0400 Subject: Substitute empty select for configurable AID. Workaround some SEs that do not support interpreting an empty select as a select of the card manager. Bug: 7198430 Change-Id: Icce0e793ca6f03d5c2271812859b04417d2708e8 --- nci/jni/SecureElement.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ nci/jni/SecureElement.h | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 5f370cc..2522e35 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -82,6 +82,7 @@ SecureElement::SecureElement () memset (&mUiccInfo, 0, sizeof(mUiccInfo)); memset (&mHciCfg, 0, sizeof(mHciCfg)); memset (mResponseData, 0, sizeof(mResponseData)); + memset (mAidForEmptySelect, 0, sizeof(mAidForEmptySelect)); } @@ -178,6 +179,7 @@ bool SecureElement::initialize (nfc_jni_native_data* native) memset (&mUiccInfo, 0, sizeof(mUiccInfo)); memset (&mHciCfg, 0, sizeof(mHciCfg)); mUsedAids.clear (); + memset(mAidForEmptySelect, 0, sizeof(mAidForEmptySelect)); // Get Fresh EE info. if (! getEeInfo()) @@ -219,6 +221,8 @@ bool SecureElement::initialize (nfc_jni_native_data* native) mRouteDataSet.import (); //read XML file HostAidRouter::getInstance().initialize (); + GetStrValue(NAME_AID_FOR_EMPTY_SELECT, (char*)&mAidForEmptySelect[0], sizeof(mAidForEmptySelect)); + mIsInit = true; ALOGD ("%s: exit", fn); return (true); @@ -847,9 +851,51 @@ bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* tNFA_STATUS nfaStat = NFA_STATUS_FAILED; bool isSuccess = false; bool waitOk = false; + UINT8 newSelectCmd[NCI_MAX_AID_LEN + 10]; ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec); + // Check if we need to replace an "empty" SELECT command. + // 1. Has there been a AID configured, and + // 2. Is that AID a valid length (i.e 16 bytes max), and + // 3. Is the APDU at least 4 bytes (for header), and + // 4. Is INS == 0xA4 (SELECT command), and + // 5. Is P1 == 0x04 (SELECT by AID), and + // 6. Is the APDU len 4 or 5 bytes. + // + // Note, the length of the configured AID is in the first + // byte, and AID starts from the 2nd byte. + if (mAidForEmptySelect[0] // 1 + && (mAidForEmptySelect[0] <= NCI_MAX_AID_LEN) // 2 + && (xmitBufferSize >= 4) // 3 + && (xmitBuffer[1] == 0xA4) // 4 + && (xmitBuffer[2] == 0x04) // 5 + && (xmitBufferSize <= 5)) // 6 + { + UINT8 idx = 0; + + // Copy APDU command header from the input buffer. + memcpy(&newSelectCmd[0], &xmitBuffer[0], 4); + idx = 4; + + // Set the Lc value to length of the new AID + newSelectCmd[idx++] = mAidForEmptySelect[0]; + + // Copy the AID + memcpy(&newSelectCmd[idx], &mAidForEmptySelect[1], mAidForEmptySelect[0]); + idx += mAidForEmptySelect[0]; + + // If there is an Le (5th byte of APDU), add it to the end. + if (xmitBufferSize == 5) + newSelectCmd[idx++] = xmitBuffer[4]; + + // Point to the new APDU + xmitBuffer = &newSelectCmd[0]; + xmitBufferSize = idx; + + ALOGD ("%s: Empty AID SELECT cmd detected, substituting AID from config file, new length=%d", fn, idx); + } + { SyncEventGuard guard (mTransceiveEvent); mActualResponseSize = 0; diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index 6a5cebd..8339a29 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -396,7 +396,7 @@ private: UINT8 mResponseData [MAX_RESPONSE_SIZE]; RouteDataSet mRouteDataSet; //routing data std::vector mUsedAids; //AID's that are used in current routes - + UINT8 mAidForEmptySelect[NCI_MAX_AID_LEN+1]; /******************************************************************************* ** -- cgit v1.1 From c7d56f7e340c3c02359cac491e1a02156226975e Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Tue, 2 Oct 2012 13:28:22 -0400 Subject: Fix locking around power state. Protect state against multi-threaded access. Bug: 7281263 Change-Id: I12735c725b6abf956cb7143f25397653839bc6e4 --- nci/jni/NativeNfcManager.cpp | 1 - nci/jni/PowerSwitch.cpp | 41 +++++++++++++++++++++++++++++++++-------- nci/jni/PowerSwitch.h | 2 +- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 6625842..babe92a 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -111,7 +111,6 @@ static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; static bool sRfEnabled = false; // whether RF discovery is enabled -#define NFA_DM_PWR_STATE_UNKNOWN (-1) // power off sleep state is unkown until is is reported back from NFA... static int sConnlessSap = 0; static int sConnlessLinkMiu = 0; static bool sAbortConnlessWait = false; diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp index f3fd316..9d58c74 100755 --- a/nci/jni/PowerSwitch.cpp +++ b/nci/jni/PowerSwitch.cpp @@ -46,9 +46,9 @@ const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED=0x04; *******************************************************************************/ PowerSwitch::PowerSwitch () : mCurrLevel (UNKNOWN_LEVEL), - mCurrActivity(0), mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN), - mDesiredScreenOffPowerState (0) + mDesiredScreenOffPowerState (0), + mCurrActivity(0) { } @@ -94,8 +94,10 @@ PowerSwitch& PowerSwitch::getInstance () void PowerSwitch::initialize (PowerLevel level) { static const char fn [] = "PowerSwitch::initialize"; - ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level); + mMutex.lock (); + + ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level); GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &mDesiredScreenOffPowerState, sizeof(mDesiredScreenOffPowerState)); ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState); @@ -115,6 +117,7 @@ void PowerSwitch::initialize (PowerLevel level) ALOGE ("%s: not handled", fn); break; } + mMutex.unlock (); } @@ -129,7 +132,11 @@ void PowerSwitch::initialize (PowerLevel level) *******************************************************************************/ PowerSwitch::PowerLevel PowerSwitch::getLevel () { - return mCurrLevel; + PowerLevel level = UNKNOWN_LEVEL; + mMutex.lock (); + level = mCurrLevel; + mMutex.unlock (); + return level; } @@ -146,11 +153,16 @@ PowerSwitch::PowerLevel PowerSwitch::getLevel () bool PowerSwitch::setLevel (PowerLevel newLevel) { static const char fn [] = "PowerSwitch::setLevel"; - ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel); bool retval = false; + mMutex.lock (); + + ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel); if (mCurrLevel == newLevel) - return true; + { + retval = true; + goto TheEnd; + } switch (newLevel) { @@ -174,6 +186,9 @@ bool PowerSwitch::setLevel (PowerLevel newLevel) ALOGE ("%s: not handled", fn); break; } + +TheEnd: + mMutex.unlock (); return retval; } @@ -188,9 +203,14 @@ bool PowerSwitch::setLevel (PowerLevel newLevel) *******************************************************************************/ bool PowerSwitch::setModeOff (PowerActivity deactivated) { + bool retVal = false; + + mMutex.lock (); mCurrActivity &= ~deactivated; + retVal = mCurrActivity != 0; ALOGD ("PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x", deactivated, mCurrActivity); - return (mCurrActivity != 0); + mMutex.unlock (); + return retVal; } @@ -205,9 +225,14 @@ bool PowerSwitch::setModeOff (PowerActivity deactivated) *******************************************************************************/ bool PowerSwitch::setModeOn (PowerActivity activated) { + bool retVal = false; + + mMutex.lock (); mCurrActivity |= activated; + retVal = mCurrActivity != 0; ALOGD ("PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated, mCurrActivity); - return (mCurrActivity != 0); + mMutex.unlock (); + return retVal; } diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h index 28362ba..d311c23 100755 --- a/nci/jni/PowerSwitch.h +++ b/nci/jni/PowerSwitch.h @@ -209,13 +209,13 @@ public: private: PowerLevel mCurrLevel; - bool mScreenState; UINT8 mCurrDeviceMgtPowerState; //device management power state; such as NFA_DM_PWR_STATE_??? int mDesiredScreenOffPowerState; //read from .conf file; 0=power-off-sleep; 1=full power; 2=CE4 power static PowerSwitch sPowerSwitch; //singleton object static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown SyncEvent mPowerStateEvent; PowerActivity mCurrActivity; + Mutex mMutex; /******************************************************************************* -- cgit v1.1 From 55b2c9109e15be7965dd7b4385e6a68e47167e09 Mon Sep 17 00:00:00 2001 From: mike wakerly Date: Wed, 3 Oct 2012 13:08:07 -0700 Subject: NfcAdapterExtras: add driver name. Bug: 7276355 Change-Id: If2732afd542a68dc440308dae9eb76eb7ff31e25 --- nci/src/com/android/nfc/dhimpl/NativeNfcManager.java | 7 +++++++ nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java | 7 +++++++ src/com/android/nfc/DeviceHost.java | 2 ++ src/com/android/nfc/NfcService.java | 6 ++++++ 4 files changed, 22 insertions(+) diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index 921e266..dde0c08 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -38,6 +38,8 @@ public class NativeNfcManager implements DeviceHost { static final int DEFAULT_LLCP_MIU = 1980; static final int DEFAULT_LLCP_RWSIZE = 2; + static final String DRIVER_NAME = "android-nci"; + static { System.loadLibrary("nfc_nci_jni"); } @@ -99,6 +101,11 @@ public class NativeNfcManager implements DeviceHost { } @Override + public String getName() { + return DRIVER_NAME; + } + + @Override public native void enableDiscovery(); @Override diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java index 903cafa..dc6ea7c 100755 --- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -43,6 +43,8 @@ public class NativeNfcManager implements DeviceHost { private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; private static final long FIRMWARE_MODTIME_DEFAULT = -1; + static final String DRIVER_NAME = "nxp"; + static final int DEFAULT_LLCP_MIU = 128; static final int DEFAULT_LLCP_RWSIZE = 1; @@ -161,6 +163,11 @@ public class NativeNfcManager implements DeviceHost { } @Override + public String getName() { + return DRIVER_NAME; + } + + @Override public native void enableDiscovery(); @Override diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java index b7336ad..487d2ad 100644 --- a/src/com/android/nfc/DeviceHost.java +++ b/src/com/android/nfc/DeviceHost.java @@ -175,6 +175,8 @@ public interface DeviceHost { public boolean deinitialize(); + public String getName(); + public void enableDiscovery(); public void disableDiscovery(); diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index ca1713d..55570a1 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -1360,6 +1360,12 @@ public class NfcService extends Application implements DeviceHostListener { public void authenticate(String pkg, byte[] token) throws RemoteException { NfcService.this.enforceNfceeAdminPerm(pkg); } + + @Override + public String getDriverName(String pkg) throws RemoteException { + NfcService.this.enforceNfceeAdminPerm(pkg); + return mDeviceHost.getName(); + } } /** resources kept while secure element is open */ -- cgit v1.1 From 98f3f63fa680fed66507399210ace05d64bf1d6c Mon Sep 17 00:00:00 2001 From: Paul Chaisson Date: Tue, 2 Oct 2012 22:28:41 -0400 Subject: Use RF_ACTIVATE/DEACTIVATE to generate RF events. Create the RF Events for SE transactions based on RF activations (listen mode and ISO-DEP only). Change-Id: Ie8317292b0de05e1a406ca84c48491738acfe271 Bug: 7276275 --- nci/jni/NativeNfcManager.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index babe92a..eadca87 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -111,6 +111,7 @@ static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; static bool sRfEnabled = false; // whether RF discovery is enabled +static bool sSeRfActive = false; // whether RF with SE is likely active static int sConnlessSap = 0; static int sConnlessLinkMiu = 0; static bool sAbortConnlessWait = false; @@ -132,6 +133,7 @@ static UINT32 sConfigUpdated = 0; static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); static bool isPeerToPeer (tNFA_ACTIVATED& activated); +static bool isListenMode(tNFA_ACTIVATED& activated); ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// @@ -305,7 +307,19 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); } else if (pn544InteropIsBusy() == false) + { NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + + // We know it is not activating for P2P. If it activated in + // listen mode then it is likely for and SE transaction. + // Send the RF Event. + if (isListenMode(eventData->activated)) + { + sSeRfActive = true; + SecureElement::getInstance().notifyRfFieldEvent (true); + } + } + break; case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated @@ -321,6 +335,16 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat NfcTag::getInstance().connectionEventHandler (connEvent, eventData); nativeNfcTag_abortWaits(); NfcTag::getInstance().abort (); + + // If RF is activated for what we think is a Secure Element transaction + // and it is deactivated to either IDLE or DISCOVERY mode, notify w/event. + if (sSeRfActive + && ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE) + || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY))) + { + sSeRfActive = false; + SecureElement::getInstance().notifyRfFieldEvent (false); + } break; case NFA_TLV_DETECT_EVT: // TLV Detection complete @@ -1262,6 +1286,26 @@ static bool isPeerToPeer (tNFA_ACTIVATED& activated) return activated.activate_ntf.protocol == NFA_PROTOCOL_NFC_DEP; } +/******************************************************************************* +** +** Function: isListenMode +** +** Description: Indicates whether the activation data indicates it is +** listen mode. +** +** Returns: True if this listen mode. +** +*******************************************************************************/ +static bool isListenMode(tNFA_ACTIVATED& activated) +{ + return ((NFC_DISCOVERY_TYPE_LISTEN_A == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_B == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_F == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == activated.activate_ntf.rf_tech_param.mode)); +} /******************************************************************************* ** @@ -1733,4 +1777,3 @@ void startStopPolling (bool isStartPolling) } /* namespace android */ - -- cgit v1.1 From 10dd44d39824fbccd8bf26871cb118b1475eb2f1 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Thu, 4 Oct 2012 16:19:56 -0400 Subject: NFA_HciAddStaticPipe()'s parameters changed Bug: 7282057 Change-Id: Ic877f67654906e21f1942adf05751943e3d6cb01 --- nci/jni/SecureElement.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 2522e35..1004bb4 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -677,7 +677,9 @@ bool SecureElement::connectEE () // If the .conf file had a static pipe to use, just use it. if (mNewPipeId != 0) { - nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, mNewPipeId); + UINT8 host = (mNewPipeId == STATIC_PIPE_0x70) ? 0x02 : 0x03; + UINT8 gate = (mNewPipeId == STATIC_PIPE_0x70) ? 0xF0 : 0xF1; + nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, mNewPipeId); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: fail create static pipe; error=0x%X", fn, nfaStat); @@ -1627,8 +1629,10 @@ bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UIN verInfo[verInfoSz-1] = '\0'; UINT8 pipe = (mEeInfo[seIndex].ee_handle == EE_HANDLE_0xF3) ? 0x70 : 0x71; + UINT8 host = (pipe == STATIC_PIPE_0x70) ? 0x02 : 0x03; + UINT8 gate = (pipe == STATIC_PIPE_0x70) ? 0xF0 : 0xF1; - tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, pipe); + tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, pipe); if (nfaStat != NFA_STATUS_OK) { ALOGE ("%s: NFA_HciAddStaticPipe() failed, pipe = 0x%x, error=0x%X", __FUNCTION__, pipe, nfaStat); -- cgit v1.1 From 07d1b6ea9f46d7118103cd0821ef7c86bfa9ee43 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 4 Oct 2012 22:51:38 -0700 Subject: Increase default transceive timeout to SE to 30s. We've found that executing some APDU commands may take longer than the current timeout of 10 seconds. Increase default transceive timeout to the SE to 30 seconds. Bug: 7004303 Change-Id: I3e6855e79b7eceae9d2aa18b3f92c3efcdf4a9d6 --- src/com/android/nfc/NfcService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 3acfa1c..62512e5 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -1287,7 +1287,7 @@ public class NfcService extends Application implements DeviceHostListener { if (handle == 0) { throw new IOException("NFC EE failed to open"); } - mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000); + mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000); mOpenEe = new OpenSecureElement(getCallingPid(), handle, b); try { -- cgit v1.1 From 88913e627332e95f916f59c826b075e7e5959d36 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 14 Sep 2012 15:01:07 -0700 Subject: NFC changes for multi-user support. - Instantiate full NfcService for user 0, light NfcApplication instance for other users - Invalidate component cache on user switch - Start all activities based on current logged in user - Query PM based on current logged in user - Only keep track of apps using the SE for the owner - Throw SecurityException on SE calls for non-owner users Bug: 6926465 Change-Id: If686efd34825a1bdd86fc06234ac7402d44a2afa --- AndroidManifest.xml | 5 +- src/com/android/nfc/NfcApplication.java | 24 ++++ src/com/android/nfc/NfcDispatcher.java | 37 ++++-- src/com/android/nfc/NfcRootActivity.java | 4 +- src/com/android/nfc/NfcService.java | 143 +++++++++++---------- src/com/android/nfc/RegisteredComponentCache.java | 31 +++-- .../nfc/handover/BluetoothHeadsetHandover.java | 8 +- src/com/android/nfc/handover/HandoverManager.java | 10 +- 8 files changed, 168 insertions(+), 94 deletions(-) create mode 100644 src/com/android/nfc/NfcApplication.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f0c027f..3157598 100755 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -20,10 +20,11 @@ + + - - activities = packageManager.queryIntentActivities(intent, 0); + List activities = packageManager.queryIntentActivitiesAsUser(intent, 0, + ActivityManager.getCurrentUser()); if (activities.size() > 0) { - context.startActivity(rootIntent); + context.startActivityAsUser(rootIntent, UserHandle.CURRENT); return true; } return false; } boolean tryStartActivity(Intent intentToStart) { - List activities = packageManager.queryIntentActivities(intentToStart, 0); + List activities = packageManager.queryIntentActivitiesAsUser( + intentToStart, 0, ActivityManager.getCurrentUser()); if (activities.size() > 0) { rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart); - context.startActivity(rootIntent); + context.startActivityAsUser(rootIntent, UserHandle.CURRENT); return true; } return false; @@ -323,7 +326,16 @@ public class NfcDispatcher { // Try to perform regular launch of the first AAR if (aarPackages.size() > 0) { String firstPackage = aarPackages.get(0); - Intent appLaunchIntent = mPackageManager.getLaunchIntentForPackage(firstPackage); + PackageManager pm; + try { + UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); + pm = mContext.createPackageContextAsUser("android", 0, + currentUser).getPackageManager(); + } catch (NameNotFoundException e) { + Log.e(TAG, "Could not create user package context"); + return false; + } + Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage); if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) { if (DBG) Log.i(TAG, "matched AAR to application launch"); return true; @@ -367,11 +379,20 @@ public class NfcDispatcher { ArrayList matches = new ArrayList(); List registered = mTechListFilters.getComponents(); + PackageManager pm; + try { + UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); + pm = mContext.createPackageContextAsUser("android", 0, + currentUser).getPackageManager(); + } catch (NameNotFoundException e) { + Log.e(TAG, "Could not create user package context"); + return false; + } // Check each registered activity to see if it matches for (ComponentInfo info : registered) { // Don't allow wild card matching if (filterMatch(tagTechs, info.techs) && - isComponentEnabled(mPackageManager, info.resolveInfo)) { + isComponentEnabled(pm, info.resolveInfo)) { // Add the activity as a match if it's not already in the list if (!matches.contains(info.resolveInfo)) { matches.add(info.resolveInfo); diff --git a/src/com/android/nfc/NfcRootActivity.java b/src/com/android/nfc/NfcRootActivity.java index 1325ead..cc216f2 100644 --- a/src/com/android/nfc/NfcRootActivity.java +++ b/src/com/android/nfc/NfcRootActivity.java @@ -17,9 +17,11 @@ package com.android.nfc; import android.app.Activity; +import android.app.ActivityManager; import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Bundle; +import android.os.UserHandle; public class NfcRootActivity extends Activity { @@ -33,7 +35,7 @@ public class NfcRootActivity extends Activity { final Intent launchIntent = intent.getParcelableExtra(EXTRA_LAUNCH_INTENT); if (launchIntent != null) { try { - startActivity(launchIntent); + startActivityAsUser(launchIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException e) { } } diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 519c15b..c344b49 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -63,6 +63,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.provider.Settings; import android.util.Log; @@ -75,7 +76,7 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.ExecutionException; -public class NfcService extends Application implements DeviceHostListener { +public class NfcService implements DeviceHostListener { private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION"; static final boolean DBG = false; @@ -169,6 +170,8 @@ public class NfcService extends Application implements DeviceHostListener { // fields below are used in multiple threads and protected by synchronized(this) final HashMap mObjectMap = new HashMap(); + // mSePackages holds packages that accessed the SE, but only for the owner user, + // as SE access is not granted for non-owner users. HashSet mSePackages = new HashSet(); int mScreenState; boolean mIsNdefPushEnabled; @@ -220,6 +223,9 @@ public class NfcService extends Application implements DeviceHostListener { throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH + " denies NFCEE access to " + pkg); } + if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { + throw new SecurityException("only the owner is allowed to call SE APIs"); + } } public static NfcService getInstance() { @@ -288,10 +294,7 @@ public class NfcService extends Application implements DeviceHostListener { sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block); } - @Override - public void onCreate() { - super.onCreate(); - + public NfcService(Application nfcApplication) { mNfcTagService = new TagService(); mNfcAdapter = new NfcAdapterService(); mExtrasService = new NfcAdapterExtrasService(); @@ -300,11 +303,11 @@ public class NfcService extends Application implements DeviceHostListener { sService = this; - mContext = this; - mDeviceHost = new NativeNfcManager(this, this); + mContext = nfcApplication; + mDeviceHost = new NativeNfcManager(mContext, this); HandoverManager handoverManager = new HandoverManager(mContext); - mNfcDispatcher = new NfcDispatcher(this, handoverManager); + mNfcDispatcher = new NfcDispatcher(mContext, handoverManager); mP2pLinkManager = new P2pLinkManager(mContext, handoverManager, mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize()); @@ -312,42 +315,48 @@ public class NfcService extends Application implements DeviceHostListener { mSecureElement = new NativeNfcSecureElement(mContext); mEeRoutingState = ROUTE_OFF; - mNfceeAccessControl = new NfceeAccessControl(this); + mNfceeAccessControl = new NfceeAccessControl(mContext); - mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE); + mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); mPrefsEditor = mPrefs.edit(); mState = NfcAdapter.STATE_OFF; mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT); - mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mRoutingWakeLock = mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock"); mEeWakeLock = mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock"); - mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mScreenState = checkScreenState(); ServiceManager.addService(SERVICE_NAME, mNfcAdapter); + // Intents only for owner + IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION); + ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION); + + mContext.registerReceiver(mOwnerReceiver, ownerFilter); + + ownerFilter = new IntentFilter(); + ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + ownerFilter.addDataScheme("package"); + + mContext.registerReceiver(mOwnerReceiver, ownerFilter); + + // Intents for all users IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION); filter.addAction(Intent.ACTION_USER_PRESENT); - filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); - filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); registerForAirplaneMode(filter); - registerReceiver(mReceiver, filter); - - filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addDataScheme("package"); - - registerReceiver(mReceiver, filter); + mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null); updatePackageCache(); @@ -358,9 +367,9 @@ public class NfcService extends Application implements DeviceHostListener { synchronized(this) { if (mSoundPool == null) { mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0); - mStartSound = mSoundPool.load(this, R.raw.start, 1); - mEndSound = mSoundPool.load(this, R.raw.end, 1); - mErrorSound = mSoundPool.load(this, R.raw.error, 1); + mStartSound = mSoundPool.load(mContext, R.raw.start, 1); + mEndSound = mSoundPool.load(mContext, R.raw.end, 1); + mErrorSound = mSoundPool.load(mContext, R.raw.error, 1); } } } @@ -392,8 +401,8 @@ public class NfcService extends Application implements DeviceHostListener { } void updatePackageCache() { - PackageManager pm = getPackageManager(); - List packages = pm.getInstalledPackages(0); + PackageManager pm = mContext.getPackageManager(); + List packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER); synchronized (this) { mInstalledPackages = packages; } @@ -667,7 +676,7 @@ public class NfcService extends Application implements DeviceHostListener { Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState); - mContext.sendBroadcast(intent); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); } } } @@ -699,12 +708,6 @@ public class NfcService extends Application implements DeviceHostListener { } } - @Override - public void onTerminate() { - super.onTerminate(); - // NFC application is persistent, it should not be destroyed by framework - Log.wtf(TAG, "NFC service is under attack!"); - } final class NfcAdapterService extends INfcAdapter.Stub { @Override @@ -1291,7 +1294,7 @@ public class NfcService extends Application implements DeviceHostListener { // Add the calling package to the list of packages that have accessed // the secure element. - for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) { + for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) { mSePackages.add(packageName); } } @@ -1861,39 +1864,11 @@ public class NfcService extends Application implements DeviceHostListener { } } - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals( - NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) { - // Perform applyRouting() in AsyncTask to serialize blocking calls - new ApplyRoutingTask().execute(); - } else if (action.equals(Intent.ACTION_SCREEN_ON) - || action.equals(Intent.ACTION_SCREEN_OFF) - || action.equals(Intent.ACTION_USER_PRESENT)) { - // Perform applyRouting() in AsyncTask to serialize blocking calls - int screenState = SCREEN_STATE_OFF; - if (action.equals(Intent.ACTION_SCREEN_OFF)) { - screenState = SCREEN_STATE_OFF; - } else if (action.equals(Intent.ACTION_SCREEN_ON)) { - screenState = mKeyguard.isKeyguardLocked() ? - SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED; - } else if (action.equals(Intent.ACTION_USER_PRESENT)) { - screenState = SCREEN_STATE_ON_UNLOCKED; - } - new ApplyRoutingTask().execute(Integer.valueOf(screenState)); - } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) { - EnableDisableTask eeWipeTask = new EnableDisableTask(); - eeWipeTask.execute(TASK_EE_WIPE); - try { - eeWipeTask.get(); // blocks until EE wipe is complete - } catch (ExecutionException e) { - Log.w(TAG, "failed to wipe NFC-EE"); - } catch (InterruptedException e) { - Log.w(TAG, "failed to wipe NFC-EE"); - } - } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || + if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_ADDED) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { @@ -1917,6 +1892,42 @@ public class NfcService extends Application implements DeviceHostListener { } } } + } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) { + EnableDisableTask eeWipeTask = new EnableDisableTask(); + eeWipeTask.execute(TASK_EE_WIPE); + try { + eeWipeTask.get(); // blocks until EE wipe is complete + } catch (ExecutionException e) { + Log.w(TAG, "failed to wipe NFC-EE"); + } catch (InterruptedException e) { + Log.w(TAG, "failed to wipe NFC-EE"); + } + } + } + }; + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals( + NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) { + // Perform applyRouting() in AsyncTask to serialize blocking calls + new ApplyRoutingTask().execute(); + } else if (action.equals(Intent.ACTION_SCREEN_ON) + || action.equals(Intent.ACTION_SCREEN_OFF) + || action.equals(Intent.ACTION_USER_PRESENT)) { + // Perform applyRouting() in AsyncTask to serialize blocking calls + int screenState = SCREEN_STATE_OFF; + if (action.equals(Intent.ACTION_SCREEN_OFF)) { + screenState = SCREEN_STATE_OFF; + } else if (action.equals(Intent.ACTION_SCREEN_ON)) { + screenState = mKeyguard.isKeyguardLocked() ? + SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED; + } else if (action.equals(Intent.ACTION_USER_PRESENT)) { + screenState = SCREEN_STATE_ON_UNLOCKED; + } + new ApplyRoutingTask().execute(Integer.valueOf(screenState)); } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { boolean isAirplaneModeOn = intent.getBooleanExtra("state", false); // Query the airplane mode from Settings.System just to make sure that diff --git a/src/com/android/nfc/RegisteredComponentCache.java b/src/com/android/nfc/RegisteredComponentCache.java index 1bac283..5da2cd4 100644 --- a/src/com/android/nfc/RegisteredComponentCache.java +++ b/src/com/android/nfc/RegisteredComponentCache.java @@ -19,6 +19,7 @@ package com.android.nfc; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -29,6 +30,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.os.UserHandle; import android.util.Log; import java.io.IOException; @@ -69,12 +71,16 @@ public class RegisteredComponentCache { intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); - mContext.registerReceiver(receiver, intentFilter); + mContext.registerReceiverAsUser(receiver, UserHandle.ALL, intentFilter, null, null); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiver(receiver, sdFilter); + mContext.registerReceiverAsUser(receiver, UserHandle.ALL, sdFilter, null, null); + // Generate a new list upon switching users as well + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_SWITCHED); + mContext.registerReceiverAsUser(receiver, UserHandle.ALL, userFilter, null, null); } public static class ComponentInfo { @@ -137,13 +143,21 @@ public class RegisteredComponentCache { } void generateComponentsList() { - PackageManager pm = mContext.getPackageManager(); + PackageManager pm; + try { + UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); + pm = mContext.createPackageContextAsUser("android", 0, + currentUser).getPackageManager(); + } catch (NameNotFoundException e) { + Log.e(TAG, "Could not create user package context"); + return; + } ArrayList components = new ArrayList(); - List resolveInfos = pm.queryIntentActivities(new Intent(mAction), - PackageManager.GET_META_DATA); + List resolveInfos = pm.queryIntentActivitiesAsUser(new Intent(mAction), + PackageManager.GET_META_DATA, ActivityManager.getCurrentUser()); for (ResolveInfo resolveInfo : resolveInfos) { try { - parseComponentInfo(resolveInfo, components); + parseComponentInfo(pm, resolveInfo, components); } catch (XmlPullParserException e) { Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e); } catch (IOException e) { @@ -158,10 +172,9 @@ public class RegisteredComponentCache { } } - void parseComponentInfo(ResolveInfo info, ArrayList components) - throws XmlPullParserException, IOException { + void parseComponentInfo(PackageManager pm, ResolveInfo info, + ArrayList components) throws XmlPullParserException, IOException { ActivityInfo ai = info.activityInfo; - PackageManager pm = mContext.getPackageManager(); XmlResourceParser parser = null; try { diff --git a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java index 644ecbd..1377160 100644 --- a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java +++ b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java @@ -16,6 +16,7 @@ package com.android.nfc.handover; +import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -28,6 +29,7 @@ import android.content.IntentFilter; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.UserHandle; import android.util.Log; import android.view.KeyEvent; import android.widget.Toast; @@ -385,10 +387,10 @@ public class BluetoothHeadsetHandover implements BluetoothProfile.ServiceListene Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY)); - mContext.sendOrderedBroadcast(intent, null); + mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY)); - mContext.sendOrderedBroadcast(intent, null); + mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null); } void requestPairConfirmation() { @@ -397,7 +399,7 @@ public class BluetoothHeadsetHandover implements BluetoothProfile.ServiceListene dialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); - mContext.startActivity(dialogIntent); + mContext.startActivityAsUser(dialogIntent, new UserHandle(UserHandle.USER_CURRENT)); } final Handler mHandler = new Handler() { diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java index a514f85..e7e807d 100644 --- a/src/com/android/nfc/handover/HandoverManager.java +++ b/src/com/android/nfc/handover/HandoverManager.java @@ -33,11 +33,8 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Notification.Builder; -import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -52,6 +49,7 @@ import android.os.Environment; import android.os.Handler; import android.os.Message; import android.os.SystemClock; +import android.os.UserHandle; import android.util.Log; import android.util.Pair; @@ -387,7 +385,8 @@ public class HandoverManager implements BluetoothHeadsetHandover.Callback { notBuilder.setContentText(mContext.getString(R.string.beam_touch_to_view)); Intent viewIntent = buildViewIntent(); - PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, 0); + PendingIntent contentIntent = PendingIntent.getActivityAsUser( + mContext, 0, viewIntent, 0, null, UserHandle.CURRENT); notBuilder.setContentIntent(contentIntent); @@ -407,7 +406,8 @@ public class HandoverManager implements BluetoothHeadsetHandover.Callback { return; } - mNotificationManager.notify(mNotificationId, notBuilder.build()); + mNotificationManager.notifyAsUser(null, mNotificationId, notBuilder.build(), + UserHandle.CURRENT); } synchronized void updateStateAndNotification(int newState) { -- cgit v1.1 From 5eb0e4ad34d354ddc903479ba99c4272e19b1375 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 8 Oct 2012 23:33:17 -0700 Subject: Set EE wipe APDUs for NCI stack. The wipe APDUs are used to lock the Secure Element state whenever an app using the SE is deinstalled, when all userdata is removed, or on first boot of the device. This sequence is identical for both the NXP and NCI implementations. Bug: 7312675 Change-Id: I746580985bc986ac159e0d294823f0dbe6d3404f --- nci/src/com/android/nfc/dhimpl/NativeNfcManager.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index dde0c08..cc485a5 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -40,6 +40,18 @@ public class NativeNfcManager implements DeviceHost { static final String DRIVER_NAME = "android-nci"; + private static final byte[][] EE_WIPE_APDUS = { + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, + (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00}, + {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, + (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00}, + {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00}, + {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, + }; + static { System.loadLibrary("nfc_nci_jni"); } @@ -281,7 +293,7 @@ public class NativeNfcManager implements DeviceHost { @Override public byte[][] getWipeApdus() { - return null; + return EE_WIPE_APDUS; } @Override -- cgit v1.1 From accbb8c908d764c5f0b8030480f3e84f0f319ff5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 9 Oct 2012 15:21:49 -0700 Subject: Don't return target lost in case of NACK for T2T. Causes applications such as TagInfo to report the tag as being lost. Also fixed a small memory leak triggered in this case. Bug: 7294613 Change-Id: I260e02896e534b23de5c7e0278609e27a9a20e7f --- nci/jni/NativeNfcTag.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp index 8c0426b..0ba7b21 100755 --- a/nci/jni/NativeNfcTag.cpp +++ b/nci/jni/NativeNfcTag.cpp @@ -806,6 +806,7 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da bool fNeedToSwitchBack = false; nfc_jni_native_data *nat = getNative (0, 0); bool waitOk = false; + bool isNack = false; uint8_t *buf = NULL; uint32_t bufLen = 0; jint *targetLost = NULL; @@ -884,24 +885,21 @@ static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray da if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) && natTag.isT2tNackResponse (sTransceiveData, sTransceiveDataLen)) { - if (targetLost) - { - ALOGD ("%s: t2t nack", __FUNCTION__); - *targetLost = 1; //causes NFC service to throw TagLostException - } - break; + isNack = true; } if (sTransceiveDataLen) { - // marshall data to java for return - result = e->NewByteArray (sTransceiveDataLen); - if (result != NULL) - { - e->SetByteArrayRegion (result, 0, sTransceiveDataLen, (jbyte *) sTransceiveData); - } - else - ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__); + if (!isNack) { + // marshall data to java for return + result = e->NewByteArray (sTransceiveDataLen); + if (result != NULL) + { + e->SetByteArrayRegion (result, 0, sTransceiveDataLen, (jbyte *) sTransceiveData); + } + else + ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__); + } // else a nack is treated as a transceive failure to the upper layers free (sTransceiveData); sTransceiveData = NULL; -- cgit v1.1 From ae1b16cf81e49a438b7a86efcdd8d83c1c0666d1 Mon Sep 17 00:00:00 2001 From: Paul Chaisson Date: Tue, 2 Oct 2012 22:28:41 -0400 Subject: Use RF_ACTIVATE/DEACTIVATE to generate RF events. (DO NOT MERGE) Create the RF Events for SE transactions based on RF activations (listen mode and ISO-DEP only). Bug: 7276275 Change-Id: Ibea0f64ba82ed31a7c582f6a44eb15abf25dda1c --- nci/jni/NativeNfcManager.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index babe92a..eadca87 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -111,6 +111,7 @@ static bool sIsNfaEnabled = false; static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; static bool sRfEnabled = false; // whether RF discovery is enabled +static bool sSeRfActive = false; // whether RF with SE is likely active static int sConnlessSap = 0; static int sConnlessLinkMiu = 0; static bool sAbortConnlessWait = false; @@ -132,6 +133,7 @@ static UINT32 sConfigUpdated = 0; static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData); static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData); static bool isPeerToPeer (tNFA_ACTIVATED& activated); +static bool isListenMode(tNFA_ACTIVATED& activated); ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// @@ -305,7 +307,19 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); } else if (pn544InteropIsBusy() == false) + { NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + + // We know it is not activating for P2P. If it activated in + // listen mode then it is likely for and SE transaction. + // Send the RF Event. + if (isListenMode(eventData->activated)) + { + sSeRfActive = true; + SecureElement::getInstance().notifyRfFieldEvent (true); + } + } + break; case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated @@ -321,6 +335,16 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat NfcTag::getInstance().connectionEventHandler (connEvent, eventData); nativeNfcTag_abortWaits(); NfcTag::getInstance().abort (); + + // If RF is activated for what we think is a Secure Element transaction + // and it is deactivated to either IDLE or DISCOVERY mode, notify w/event. + if (sSeRfActive + && ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE) + || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY))) + { + sSeRfActive = false; + SecureElement::getInstance().notifyRfFieldEvent (false); + } break; case NFA_TLV_DETECT_EVT: // TLV Detection complete @@ -1262,6 +1286,26 @@ static bool isPeerToPeer (tNFA_ACTIVATED& activated) return activated.activate_ntf.protocol == NFA_PROTOCOL_NFC_DEP; } +/******************************************************************************* +** +** Function: isListenMode +** +** Description: Indicates whether the activation data indicates it is +** listen mode. +** +** Returns: True if this listen mode. +** +*******************************************************************************/ +static bool isListenMode(tNFA_ACTIVATED& activated) +{ + return ((NFC_DISCOVERY_TYPE_LISTEN_A == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_B == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_F == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == activated.activate_ntf.rf_tech_param.mode) + || (NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == activated.activate_ntf.rf_tech_param.mode)); +} /******************************************************************************* ** @@ -1733,4 +1777,3 @@ void startStopPolling (bool isStartPolling) } /* namespace android */ - -- cgit v1.1 From a949c74321b17f8ef1c93692064969f60815c7e4 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 4 Oct 2012 16:52:51 -0700 Subject: Fast-fail SE open if it's activated in listen mode. Users of the NFC-extras API usually want to talk to the SE once it has completed a transaction. The hard part is knowing when it is safe to connect to the SE, as it will break the connection to any reader. And when relinquishing the connection to the SE, the reader may find the device again and process another transaction. This patch adds the following two conditions for allowing to open the SE from the DH: 1) The SE may not be activated in listen mode 2) The RF field must have been off for at least 50 ms Bug: 7275484 Change-Id: Ibde32a8e2aef045c17ab76ef08c72f96edfedaef --- nci/jni/JavaClassConstants.h | 2 + nci/jni/NativeNfcManager.cpp | 47 +++++++- nci/jni/NativeSecureElement.cpp | 20 +++- nci/jni/SecureElement.cpp | 127 ++++++++++++++++++++- nci/jni/SecureElement.h | 40 ++++++- .../com/android/nfc/dhimpl/NativeNfcManager.java | 8 ++ src/com/android/nfc/DeviceHost.java | 10 ++ src/com/android/nfc/NfcService.java | 34 ++++++ 8 files changed, 271 insertions(+), 17 deletions(-) diff --git a/nci/jni/JavaClassConstants.h b/nci/jni/JavaClassConstants.h index 64244c3..30deca9 100644 --- a/nci/jni/JavaClassConstants.h +++ b/nci/jni/JavaClassConstants.h @@ -24,6 +24,8 @@ namespace android extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; extern jmethodID gCachedNfcManagerNotifySeFieldActivated; extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated; + extern jmethodID gCachedNfcManagerNotifySeListenActivated; + extern jmethodID gCachedNfcManagerNotifySeListenDeactivated; extern const char* gNativeP2pDeviceClassName; extern const char* gNativeLlcpServiceSocketClassName; diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index eadca87..81bb6b2 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -78,6 +78,8 @@ namespace android jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated; jmethodID gCachedNfcManagerNotifySeFieldActivated; jmethodID gCachedNfcManagerNotifySeFieldDeactivated; + jmethodID gCachedNfcManagerNotifySeListenActivated; + jmethodID gCachedNfcManagerNotifySeListenDeactivated; const char* gNativeP2pDeviceClassName = "com/android/nfc/dhimpl/NativeP2pDevice"; const char* gNativeLlcpServiceSocketClassName = "com/android/nfc/dhimpl/NativeLlcpServiceSocket"; const char* gNativeLlcpConnectionlessSocketClassName = "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket"; @@ -112,6 +114,7 @@ static bool sDiscoveryEnabled = false; //is polling for tag? static bool sIsDisabling = false; static bool sRfEnabled = false; // whether RF discovery is enabled static bool sSeRfActive = false; // whether RF with SE is likely active +static bool sP2pActive = false; // whether p2p was last active static int sConnlessSap = 0; static int sConnlessLinkMiu = 0; static bool sAbortConnlessWait = false; @@ -304,7 +307,18 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat nativeNfcTag_resetPresenceCheck(); if (isPeerToPeer(eventData->activated)) { + sP2pActive = true; ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); + // Disable RF field events in case of p2p + UINT8 nfa_disable_rf_events[] = { 0x00 }; + ALOGD ("%s: Disabling RF field events", __FUNCTION__); + status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_disable_rf_events), + &nfa_disable_rf_events[0]); + if (status == NFA_STATUS_OK) { + ALOGD ("%s: Disabled RF field events", __FUNCTION__); + } else { + ALOGE ("%s: Failed to disable RF field events", __FUNCTION__); + } } else if (pn544InteropIsBusy() == false) { @@ -316,7 +330,7 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat if (isListenMode(eventData->activated)) { sSeRfActive = true; - SecureElement::getInstance().notifyRfFieldEvent (true); + SecureElement::getInstance().notifyListenModeState (true); } } @@ -338,13 +352,30 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat // If RF is activated for what we think is a Secure Element transaction // and it is deactivated to either IDLE or DISCOVERY mode, notify w/event. - if (sSeRfActive - && ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE) - || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY))) + if ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE) + || (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY)) { - sSeRfActive = false; - SecureElement::getInstance().notifyRfFieldEvent (false); + if (sSeRfActive) { + sSeRfActive = false; + SecureElement::getInstance().notifyListenModeState (false); + } else if (sP2pActive) { + sP2pActive = false; + // Make sure RF field events are re-enabled + ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__); + // Disable RF field events in case of p2p + UINT8 nfa_enable_rf_events[] = { 0x01 }; + + ALOGD ("%s: Enabling RF field events", __FUNCTION__); + status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_enable_rf_events), + &nfa_enable_rf_events[0]); + if (status == NFA_STATUS_OK) { + ALOGD ("%s: Enabled RF field events", __FUNCTION__); + } else { + ALOGE ("%s: Failed to enable RF field events", __FUNCTION__); + } + } } + break; case NFA_TLV_DETECT_EVT: // TLV Detection complete @@ -513,6 +544,10 @@ static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o) "notifySeFieldActivated", "()V"); gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID (cls, "notifySeFieldDeactivated", "()V"); + gCachedNfcManagerNotifySeListenActivated = e->GetMethodID (cls, + "notifySeListenActivated", "()V"); + gCachedNfcManagerNotifySeListenDeactivated = e->GetMethodID (cls, + "notifySeListenDeactivated", "()V"); sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls, "notifySeApduReceived", "([B)V"); diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp index 104d4ea..1a2a73a 100755 --- a/nci/jni/NativeSecureElement.cpp +++ b/nci/jni/NativeSecureElement.cpp @@ -44,24 +44,34 @@ static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, job ALOGD("%s: enter", __FUNCTION__); bool stat = true; jint secElemHandle = 0; + SecureElement &se = SecureElement::getInstance(); + if (se.isActivatedInListenMode()) { + ALOGD("Denying SE open due to SE listen mode active"); + goto TheEnd; + } + + if (se.isRfFieldOn()) { + ALOGD("Denying SE open due to SE in active RF field"); + goto TheEnd; + } //tell the controller to power up to get ready for sec elem operations PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER); PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_CONNECTED); //if controller is not routing AND there is no pipe connected, //then turn on the sec elem - if (! SecureElement::getInstance().isBusy()) - stat = SecureElement::getInstance().activate(0); + if (! se.isBusy()) + stat = se.activate(0); if (stat) { //establish a pipe to sec elem - stat = SecureElement::getInstance().connectEE(); + stat = se.connectEE(); if (stat) - secElemHandle = SecureElement::getInstance().mActiveEeHandle; + secElemHandle = se.mActiveEeHandle; else - SecureElement::getInstance().deactivate (0); + se.deactivate (0); } //if code fails to connect to the secure element, and nothing is active, then diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 1004bb4..f6b2721 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -76,13 +76,16 @@ SecureElement::SecureElement () mCurrentRouteSelection (NoRoute), mActualResponseSize(0), mUseOberthurWarmReset (false), - mOberthurWarmResetCommand (3) + mActivatedInListenMode (false), + mOberthurWarmResetCommand (3), + mRfFieldIsOn(false) { memset (&mEeInfo, 0, sizeof(mEeInfo)); memset (&mUiccInfo, 0, sizeof(mUiccInfo)); memset (&mHciCfg, 0, sizeof(mHciCfg)); memset (mResponseData, 0, sizeof(mResponseData)); memset (mAidForEmptySelect, 0, sizeof(mAidForEmptySelect)); + memset (&mLastRfFieldToggle, 0, sizeof(mLastRfFieldToggle)); } @@ -323,6 +326,70 @@ bool SecureElement::getEeInfo() /******************************************************************************* ** +** Function TimeDiff +** +** Description Computes time difference in milliseconds. +** +** Returns Time difference in milliseconds +** +*******************************************************************************/ +static UINT32 TimeDiff(timespec start, timespec end) +{ + end.tv_sec -= start.tv_sec; + end.tv_nsec -= start.tv_nsec; + + if (end.tv_nsec < 0) { + end.tv_nsec += 10e8; + end.tv_sec -=1; + } + + return (end.tv_sec * 1000) + (end.tv_nsec / 10e5); +} + +/******************************************************************************* +** +** Function: isRfFieldOn +** +** Description: Can be used to determine if the SE is in an RF field +** +** Returns: True if the SE is activated in an RF field +** +*******************************************************************************/ +bool SecureElement::isRfFieldOn() { + AutoMutex mutex(mMutex); + if (mRfFieldIsOn) { + return true; + } + struct timespec now; + int ret = clock_gettime(CLOCK_MONOTONIC, &now); + if (ret == -1) { + ALOGE("isRfFieldOn(): clock_gettime failed"); + return false; + } + if (TimeDiff(mLastRfFieldToggle, now) < 50) { + // If it was less than 50ms ago that RF field + // was turned off, still return ON. + return true; + } else { + return false; + } +} + +/******************************************************************************* +** +** Function: isActivatedInListenMode +** +** Description: Can be used to determine if the SE is activated in listen mode +** +** Returns: True if the SE is activated in listen mode +** +*******************************************************************************/ +bool SecureElement::isActivatedInListenMode() { + return mActivatedInListenMode; +} + +/******************************************************************************* +** ** Function: getListOfEeHandles ** ** Description: Get the list of handles of all execution environments. @@ -939,6 +1006,48 @@ TheEnd: /******************************************************************************* ** +** Function: notifyListenModeState +** +** Description: Notify the NFC service about whether the SE was activated +** in listen mode. +** isActive: Whether the secure element is activated. +** +** Returns: None +** +*******************************************************************************/ +void SecureElement::notifyListenModeState (bool isActivated) { + static const char fn [] = "SecureElement::notifyListenMode"; + JNIEnv *e = NULL; + + ALOGD ("%s: enter; listen mode active=%u", fn, isActivated); + mNativeData->vm->AttachCurrentThread (&e, NULL); + + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + mActivatedInListenMode = isActivated; + if (isActivated) { + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenActivated); + } + else { + e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenDeactivated); + } + + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + mNativeData->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + +/******************************************************************************* +** ** Function: notifyRfFieldEvent ** ** Description: Notify the NFC service about RF field events from the stack. @@ -961,17 +1070,27 @@ void SecureElement::notifyRfFieldEvent (bool isActive) return; } - if (isActive) + mMutex.lock(); + int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle); + if (ret == -1) { + ALOGE("%s: clock_gettime failed", fn); + // There is no good choice here... + } + if (isActive) { + mRfFieldIsOn = true; e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldActivated); - else + } + else { + mRfFieldIsOn = false; e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldDeactivated); + } + mMutex.unlock(); if (e->ExceptionCheck()) { e->ExceptionClear(); ALOGE ("%s: fail notify", fn); } - mNativeData->vm->DetachCurrentThread (); ALOGD ("%s: exit", fn); } diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h index 8339a29..1758590 100755 --- a/nci/jni/SecureElement.h +++ b/nci/jni/SecureElement.h @@ -157,6 +157,18 @@ public: bool transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer, INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec); + /******************************************************************************* + ** + ** Function: notifyListenModeState + ** + ** Description: Notify the NFC service about whether the SE was activated + ** in listen mode. + ** isActive: Whether the secure element is activated. + ** + ** Returns: None + ** + *******************************************************************************/ + void notifyListenModeState (bool isActivated); /******************************************************************************* ** @@ -346,6 +358,28 @@ public: bool getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid); + /******************************************************************************* + ** + ** Function: isActivatedInListenMode + ** + ** Description: Can be used to determine if the SE is activated in listen mode + ** + ** Returns: True if the SE is activated in listen mode + ** + *******************************************************************************/ + bool isActivatedInListenMode(); + + /******************************************************************************* + ** + ** Function: isRfFieldOn + ** + ** Description: Can be used to determine if the SE is in an RF field + ** + ** Returns: True if the SE is activated in an RF field + ** + *******************************************************************************/ + bool isRfFieldOn(); + private: static const unsigned int MAX_RESPONSE_SIZE = 1024; enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute}; @@ -373,6 +407,7 @@ private: RouteSelection mCurrentRouteSelection; int mActualResponseSize; //number of bytes in the response received from secure element bool mUseOberthurWarmReset; //whether to use warm-reset command + bool mActivatedInListenMode; // whether we're activated in listen mode UINT8 mOberthurWarmResetCommand; //warm-reset command byte tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe tNFA_EE_DISCOVER_REQ mUiccInfo; @@ -397,7 +432,9 @@ private: RouteDataSet mRouteDataSet; //routing data std::vector mUsedAids; //AID's that are used in current routes UINT8 mAidForEmptySelect[NCI_MAX_AID_LEN+1]; - + Mutex mMutex; // protects fields below + bool mRfFieldIsOn; // last known RF field state + struct timespec mLastRfFieldToggle; // last time RF field went off /******************************************************************************* ** ** Function: SecureElement @@ -538,7 +575,6 @@ private: *******************************************************************************/ bool getEeInfo (); - /******************************************************************************* ** ** Function: eeStatusToString diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java index 921e266..40b9347 100755 --- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java +++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java @@ -336,6 +336,14 @@ public class NativeNfcManager implements DeviceHost { mListener.onRemoteFieldDeactivated(); } + private void notifySeListenActivated() { + mListener.onSeListenActivated(); + } + + private void notifySeListenDeactivated() { + mListener.onSeListenDeactivated(); + } + private void notifySeApduReceived(byte[] apdu) { mListener.onSeApduReceived(apdu); } diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java index b7336ad..fa3d17c 100644 --- a/src/com/android/nfc/DeviceHost.java +++ b/src/com/android/nfc/DeviceHost.java @@ -49,6 +49,16 @@ public interface DeviceHost { public void onRemoteFieldDeactivated(); + /** + * Notifies that the SE has been activated in listen mode + */ + public void onSeListenActivated(); + + /** + * Notifies that the SE has been deactivated + */ + public void onSeListenDeactivated(); + public void onSeApduReceived(byte[] apdu); public void onSeEmvCardRemoval(); diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 62512e5..d7bb2ef 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -112,6 +112,8 @@ public class NfcService extends Application implements DeviceHostListener { static final int MSG_SE_APDU_RECEIVED = 10; static final int MSG_SE_EMV_CARD_REMOVAL = 11; static final int MSG_SE_MIFARE_ACCESS = 12; + static final int MSG_SE_LISTEN_ACTIVATED = 13; + static final int MSG_SE_LISTEN_DEACTIVATED = 14; static final int TASK_ENABLE = 1; static final int TASK_DISABLE = 2; @@ -158,6 +160,11 @@ public class NfcService extends Application implements DeviceHostListener { public static final String EXTRA_MIFARE_BLOCK = "com.android.nfc_extras.extra.MIFARE_BLOCK"; + public static final String ACTION_SE_LISTEN_ACTIVATED = + "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED"; + public static final String ACTION_SE_LISTEN_DEACTIVATED = + "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED"; + // NFC Execution Environment // fields below are protected by this private NativeNfcSecureElement mSecureElement; @@ -275,6 +282,17 @@ public class NfcService extends Application implements DeviceHostListener { } @Override + public void onSeListenActivated() { + sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null); + } + + @Override + public void onSeListenDeactivated() { + sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null); + } + + + @Override public void onSeApduReceived(byte[] apdu) { sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu); } @@ -1743,6 +1761,22 @@ public class NfcService extends Application implements DeviceHostListener { break; } + case MSG_SE_LISTEN_ACTIVATED: { + if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED"); + Intent listenModeActivated = new Intent(); + listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED); + sendSeBroadcast(listenModeActivated); + break; + } + + case MSG_SE_LISTEN_DEACTIVATED: { + if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED"); + Intent listenModeDeactivated = new Intent(); + listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED); + sendSeBroadcast(listenModeDeactivated); + break; + } + default: Log.e(TAG, "Unknown message received"); break; -- cgit v1.1 From 81aa9898af2f99506cb025e9d8e37252d80c42fa Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 12 Oct 2012 15:06:36 -0700 Subject: Don't hold a timed wakelock. We used to acquire a timed wakelock when either resuming or suspending. We don't want to take a timed wakelock when suspending, since we want to suspend asap, but also don't want to underlock the wakelock. Instead of taking a timed wakelock, just abort the process in case the NFC controller hangs. Bug: 7341879 Change-Id: Ibd2f468264f60a39db3cb271a6f05c50dfb559bf --- nci/jni/NativeNfcManager.cpp | 3 ++- src/com/android/nfc/NfcService.java | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 81bb6b2..814f49b 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -1385,7 +1385,8 @@ static jboolean nfcManager_doActivateLlcp(JNIEnv *e, jobject o) *******************************************************************************/ static void nfcManager_doAbort(JNIEnv *e, jobject o) { - ALOGD("%s", __FUNCTION__); + ALOGE("%s: abort()", __FUNCTION__); + abort(); } diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 0514160..c7b0bba 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -1883,11 +1883,7 @@ public class NfcService implements DeviceHostListener { } mScreenState = params[0].intValue(); - // HACK: We've seen applying the routing configuration - // getting stuck. The operation should normally easily - // complete within a minute, so don't hold the wakelock - // any longer than that. - mRoutingWakeLock.acquire(60000); + mRoutingWakeLock.acquire(); try { applyRouting(false); } finally { -- cgit v1.1 From b034c8b4aea76979cf7bce841dbb627eec507d3d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 15 Oct 2012 21:07:19 -0700 Subject: Fix Beam animation for non-owner user. The Beam animation adds a system window on top of the current window stack, and does this from a process run as the owner user. Added required permission that allows showing the window for all users. Also added a glClear() to fix a rendering glitch on Manta. Bug: 7351616 Bug: 7310663 Change-Id: I06960ee9d843c2413fcfd36a81bc7161fed5ef98 --- AndroidManifest.xml | 1 + src/com/android/nfc/FireflyRenderer.java | 1 + src/com/android/nfc/SendUi.java | 2 ++ 3 files changed, 4 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3157598..710e2ee 100755 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -22,6 +22,7 @@ + Date: Mon, 15 Oct 2012 16:39:47 -0400 Subject: Check for invalid handle before configuring secure element. If handle is invalid, don't adjust secure element's listening parameter. This prevents a warning message from stack. Use LLCP_MAX_MIU to prevent a warning message from stack. Bug: 7357666 Change-Id: I79af30f7d3db1d597b46d8cf43991c9157359e10 --- nci/jni/PeerToPeer.cpp | 2 +- nci/jni/SecureElement.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp index 13b5a60..7994e2a 100644 --- a/nci/jni/PeerToPeer.cpp +++ b/nci/jni/PeerToPeer.cpp @@ -1590,7 +1590,7 @@ bool P2pServer::registerWithStack() - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) ************************/ - stat = NFA_P2pSetLLCPConfig (LLCP_MIU, + stat = NFA_P2pSetLLCPConfig (LLCP_MAX_MIU, LLCP_OPT_VALUE, LLCP_WAITING_TIME, LLCP_LTO_VALUE, diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index f6b2721..6c52030 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -2129,6 +2129,7 @@ bool SecureElement::routeToDefault () tNFA_STATUS nfaStat = NFA_STATUS_FAILED; bool retval = false; + ALOGD ("%s: enter", fn); if (! mIsInit) { ALOGE ("%s: not init", fn); @@ -2141,6 +2142,7 @@ bool SecureElement::routeToDefault () return true; } + if (mActiveEeHandle != NFA_HANDLE_INVALID) { ALOGD ("%s: stop UICC listen; EE h=0x%X", fn, mActiveEeHandle); SyncEventGuard guard (mUiccListenEvent); @@ -2153,6 +2155,8 @@ bool SecureElement::routeToDefault () else ALOGE ("%s: fail to stop UICC listen", fn); } + else + retval = true; adjustRoutes (DefaultRoute); -- cgit v1.1 From 547b58f41866671e0028ed6f395b34e271ce81b1 Mon Sep 17 00:00:00 2001 From: Evan Chu Date: Mon, 15 Oct 2012 15:36:14 -0400 Subject: Fix tag not deactivating to sleep during reconnect. During reconnect, the JNI deactivates the tag to sleep mode and re-selects it. Sometimes when the tag leaves the RF field, it deactivates to idle instead of sleep; causing subsequent select to fail. Author: Mark Gorodetzky Bug: 7357299 Change-Id: Id774d0bc3b8e2cbcea93cd2ee061ffecfa821a1e --- nci/jni/NativeNfcManager.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp index 81bb6b2..a872791 100755 --- a/nci/jni/NativeNfcManager.cpp +++ b/nci/jni/NativeNfcManager.cpp @@ -339,16 +339,17 @@ static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventDat case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated ALOGD("%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __FUNCTION__, eventData->deactivated.type,gIsTagDeactivating); NfcTag::getInstance().setDeactivationState (eventData->deactivated); - if (gIsTagDeactivating || gIsSelectingRfInterface) + if (eventData->deactivated.type != NFA_DEACTIVATE_TYPE_SLEEP) { - if (gIsTagDeactivating) - nativeNfcTag_doDeactivateStatus(0); - break; + nativeNfcTag_resetPresenceCheck(); + NfcTag::getInstance().connectionEventHandler (connEvent, eventData); + nativeNfcTag_abortWaits(); + NfcTag::getInstance().abort (); + } + else if (gIsTagDeactivating) + { + nativeNfcTag_doDeactivateStatus(0); } - nativeNfcTag_resetPresenceCheck(); - NfcTag::getInstance().connectionEventHandler (connEvent, eventData); - nativeNfcTag_abortWaits(); - NfcTag::getInstance().abort (); // If RF is activated for what we think is a Secure Element transaction // and it is deactivated to either IDLE or DISCOVERY mode, notify w/event. -- cgit v1.1 From ce3c183c9b8f3e36ba841d15b91d855854552321 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 22 Oct 2012 17:22:04 -0700 Subject: Reset RF field status on SE activation. We've seen the NFCC get in a state where it continuously reports field off/field on events. The danger is that the device goes to sleep right after a field on event. On wake-up, the field off/field on loop is gone, and the device prevents any access to the SE from the DH because it thinks the field is still present. Bug: 7386840 Change-Id: I87b681124078fe69c0244efd7b14ebe3ffd1c161 --- nci/jni/SecureElement.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp index 6c52030..3c9256b 100755 --- a/nci/jni/SecureElement.cpp +++ b/nci/jni/SecureElement.cpp @@ -486,6 +486,11 @@ bool SecureElement::activate (jint seID) if (mActiveSeOverride) override_se = NFA_HANDLE_GROUP_EE | mActiveSeOverride; + if (mRfFieldIsOn) { + ALOGE("%s: RF field indication still on, resetting", fn); + mRfFieldIsOn = false; + } + ALOGD ("%s: override seid=0x%X", fn, override_se ); //activate every discovered secure element for (int index=0; index < mActualNumEe; index++) -- cgit v1.1 From b340c6cb76ce38a28d0a775dfaeb027b364fe884 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 23 Oct 2012 11:43:02 -0700 Subject: Fix wrong Beam image scaling on sw600 and larger devices. On sw600 and larger, the navbar is at the bottom, not to the side. Bug: 7399926 Change-Id: I825a1156995ec6e84faef16866dea4bf240a11c2 --- src/com/android/nfc/SendUi.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/com/android/nfc/SendUi.java b/src/com/android/nfc/SendUi.java index a12aabb..5b5c234 100644 --- a/src/com/android/nfc/SendUi.java +++ b/src/com/android/nfc/SendUi.java @@ -445,6 +445,9 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener, // Navbar has different sizes, depending on orientation final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.navigation_bar_height) : 0; + final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height_landscape) : 0; + final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.navigation_bar_width) : 0; @@ -485,13 +488,20 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener, int newTop = statusBarHeight; int newWidth = bitmap.getWidth(); int newHeight = bitmap.getHeight(); + float smallestWidth = (float)Math.min(newWidth, newHeight); + float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f); if (bitmap.getWidth() < bitmap.getHeight()) { // Portrait mode: status bar is at the top, navbar bottom, width unchanged newHeight = bitmap.getHeight() - statusBarHeight - navBarHeight; } else { - // Landscape mode: status bar is at the top, navbar right - newHeight = bitmap.getHeight() - statusBarHeight; - newWidth = bitmap.getWidth() - navBarWidth; + // Landscape mode: status bar is at the top + // Navbar: bottom on >599dp width devices, otherwise to the side + if (smallestWidthDp > 599) { + newHeight = bitmap.getHeight() - statusBarHeight - navBarHeightLandscape; + } else { + newHeight = bitmap.getHeight() - statusBarHeight; + newWidth = bitmap.getWidth() - navBarWidth; + } } bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight); -- cgit v1.1 From 5040f60c9a23a63f0e8e5029ac1d0b73ac58d7d3 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 23 Oct 2012 20:51:03 -0700 Subject: Delay sending EE-wipe APDUs. Work around an issue where sending the wipe APDUs at the same time as the SE sends its HCI configuration to the NFCC can cause the persistent HCI state to become incorrect. Bug: 7387638 Change-Id: I11a73e3ad7875c5b1d755efde0a7a803427b7468 --- src/com/android/nfc/NfcService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index c7b0bba..caa2db0 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -659,6 +659,13 @@ public class NfcService implements DeviceHostListener { return; } + + // TODO: remove this hack + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + try { mEeWakeLock.acquire(); try { -- cgit v1.1 From 5cd1d0c05c257bf8004594bdfd1e6b0e9c95428d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 24 Oct 2012 12:35:08 -0700 Subject: Hold a wakelock during initialisation. The NCI stack may do firmware download as part of the intilization call. Make sure we don't suspend while the download is in progress. Also, hold a wakelock over the entire EEwipe procedure. This prevents suspending in the middle. Bug: 7407558 Change-Id: I2034c8292414dc7db20a0c19951d44021389adea --- src/com/android/nfc/NfcService.java | 120 ++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index caa2db0..551469d 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -135,6 +135,15 @@ public class NfcService implements DeviceHostListener { /** minimum screen state that enables NFC polling (discovery) */ static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED; + // Time to wait for NFC controller to initialize before watchdog + // goes off. This time is chosen large, because firmware download + // may be a part of initialization. + static final int INIT_WATCHDOG_MS = 90000; + + // Time to wait for routing to be applied before watchdog + // goes off + static final int ROUTING_WATCHDOG_MS = 10000; + // for use with playSound() public static final int SOUND_START = 0; public static final int SOUND_END = 1; @@ -563,11 +572,21 @@ public class NfcService implements DeviceHostListener { Log.i(TAG, "Enabling NFC"); updateState(NfcAdapter.STATE_TURNING_ON); - - if (!mDeviceHost.initialize()) { - Log.w(TAG, "Error enabling NFC"); - updateState(NfcAdapter.STATE_OFF); - return false; + WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS); + watchDog.start(); + try { + mRoutingWakeLock.acquire(); + try { + if (!mDeviceHost.initialize()) { + Log.w(TAG, "Error enabling NFC"); + updateState(NfcAdapter.STATE_OFF); + return false; + } + } finally { + mRoutingWakeLock.release(); + } + } finally { + watchDog.cancel(); } synchronized(NfcService.this) { @@ -600,7 +619,7 @@ public class NfcService implements DeviceHostListener { * Implemented with a new thread (instead of a Handler or AsyncTask), * because the UI Thread and AsyncTask thread-pools can also get hung * when the NFC controller stops responding */ - WatchDogThread watchDog = new WatchDogThread(); + WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS); watchDog.start(); mP2pLinkManager.enableDisable(false, false); @@ -643,53 +662,56 @@ public class NfcService implements DeviceHostListener { } boolean tempEnable = mState == NfcAdapter.STATE_OFF; - if (tempEnable) { - if (!enableInternal()) { + // Hold a wake-lock over the entire wipe procedure + mEeWakeLock.acquire(); + try { + if (tempEnable && !enableInternal()) { Log.w(TAG, "Could not enable NFC to wipe NFC-EE"); return; } - } - Log.i(TAG, "Executing SE wipe"); - int handle = doOpenSecureElementConnection(); - if (handle == 0) { - Log.w(TAG, "Could not open the secure element"); - if (tempEnable) { - disableInternal(); - } - return; - } - - - // TODO: remove this hack - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - - try { - mEeWakeLock.acquire(); try { - mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000); + // NFC enabled + int handle = 0; + try { + Log.i(TAG, "Executing SE wipe"); + handle = doOpenSecureElementConnection(); + if (handle == 0) { + Log.w(TAG, "Could not open the secure element"); + return; + } + // TODO: remove this hack + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } - for (byte[] cmd : apdus) { - byte[] resp = doTransceiveNoLock(handle, cmd); - if (resp == null) { - Log.w(TAG, "Transceive failed, could not wipe NFC-EE"); - break; + mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000); + try { + for (byte[] cmd : apdus) { + byte[] resp = doTransceiveNoLock(handle, cmd); + if (resp == null) { + Log.w(TAG, "Transceive failed, could not wipe NFC-EE"); + break; + } + } + } finally { + mDeviceHost.resetTimeouts(); + } + } finally { + if (handle != 0) { + doDisconnect(handle); } } - - mDeviceHost.resetTimeouts(); } finally { - mEeWakeLock.release(); + if (tempEnable) { + disableInternal(); + } } } finally { - doDisconnect(handle); - } - - if (tempEnable) { - disableInternal(); + mEeWakeLock.release(); } + Log.i(TAG, "SE wipe done"); } void updateState(int newState) { @@ -1442,19 +1464,27 @@ public class NfcService implements DeviceHostListener { class WatchDogThread extends Thread { boolean mWatchDogCanceled = false; + final int mTimeout; + + public WatchDogThread(String threadName, int timeout) { + super(threadName); + mTimeout = timeout; + } + @Override public void run() { boolean slept = false; while (!slept) { try { - Thread.sleep(10000); + Thread.sleep(mTimeout); slept = true; } catch (InterruptedException e) { } } synchronized (this) { if (!mWatchDogCanceled) { // Trigger watch-dog - Log.e(TAG, "--- NFC controller stuck while applying routing ---"); + Log.e(TAG, "Watchdog fired: name=" + getName() + " threadId=" + + getId() + " timeout=" + mTimeout); mDeviceHost.doAbort(); } } @@ -1473,7 +1503,7 @@ public class NfcService implements DeviceHostListener { // PN544 cannot be reconfigured while EE is open return; } - WatchDogThread watchDog = new WatchDogThread(); + WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS); try { watchDog.start(); -- cgit v1.1 From 1a6bcf3cca90fedfbad33c1cdd6d05af5774fc01 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 25 Oct 2012 20:49:48 -0700 Subject: Serialize applying card emulation route. Instead of immediately applying the routing, serialze the request with any outstanding commands (including NFC enable/disable). This prevents race conditions when NFC is being disabled and the card emu routing gets changed at the same time. Wait until the AsyncTask is complete, to make sure that the routing is applied (if possible) by the time the call returns. Bug: 7418238 Change-Id: I7d92533179c02f4b6b01a86967737e64532317a1 --- src/com/android/nfc/NfcService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java index 551469d..d63f84f 100755 --- a/src/com/android/nfc/NfcService.java +++ b/src/com/android/nfc/NfcService.java @@ -1403,7 +1403,16 @@ public class NfcService implements DeviceHostListener { public void setCardEmulationRoute(String pkg, int route) throws RemoteException { NfcService.this.enforceNfceeAdminPerm(pkg); mEeRoutingState = route; - applyRouting(true); + ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask(); + applyRoutingTask.execute(); + try { + // Block until route is set + applyRoutingTask.get(); + } catch (ExecutionException e) { + Log.e(TAG, "failed to set card emulation mode"); + } catch (InterruptedException e) { + Log.e(TAG, "failed to set card emulation mode"); + } } @Override -- cgit v1.1