Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdlib.h>
     18 
     19 #include "errno.h"
     20 #include "com_android_nfc.h"
     21 #include "com_android_nfc_list.h"
     22 #include "phLibNfcStatus.h"
     23 #include <ScopedLocalRef.h>
     24 
     25 /*
     26  * JNI Initialization
     27  */
     28 jint JNI_OnLoad(JavaVM *jvm, void *reserved)
     29 {
     30    JNIEnv *e;
     31 
     32    ALOGI("NFC Service: loading nxp JNI");
     33 
     34    // Check JNI version
     35    if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6))
     36       return JNI_ERR;
     37 
     38    android::vm = jvm;
     39 
     40    if (android::register_com_android_nfc_NativeNfcManager(e) == -1)
     41       return JNI_ERR;
     42    if (android::register_com_android_nfc_NativeNfcTag(e) == -1)
     43       return JNI_ERR;
     44    if (android::register_com_android_nfc_NativeP2pDevice(e) == -1)
     45       return JNI_ERR;
     46    if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1)
     47       return JNI_ERR;
     48    if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1)
     49       return JNI_ERR;
     50    if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1)
     51       return JNI_ERR;
     52    if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1)
     53       return JNI_ERR;
     54 
     55    return JNI_VERSION_1_6;
     56 }
     57 
     58 namespace android {
     59 
     60 extern struct nfc_jni_native_data *exported_nat;
     61 
     62 JavaVM *vm;
     63 
     64 /*
     65  * JNI Utils
     66  */
     67 JNIEnv *nfc_get_env()
     68 {
     69     JNIEnv *e;
     70     if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) {
     71         ALOGE("Current thread is not attached to VM");
     72         phLibNfc_Mgt_Recovery();
     73         abort();
     74     }
     75     return e;
     76 }
     77 
     78 bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext)
     79 {
     80    /* Create semaphore */
     81    if(sem_init(&pCallbackData->sem, 0, 0) == -1)
     82    {
     83       ALOGE("Semaphore creation failed (errno=0x%08x)", errno);
     84       return false;
     85    }
     86 
     87    /* Set default status value */
     88    pCallbackData->status = NFCSTATUS_FAILED;
     89 
     90    /* Copy the context */
     91    pCallbackData->pContext = pContext;
     92 
     93    /* Add to active semaphore list */
     94    if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData))
     95    {
     96       ALOGE("Failed to add the semaphore to the list");
     97    }
     98 
     99    return true;
    100 }
    101 
    102 void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData)
    103 {
    104    /* Destroy semaphore */
    105    if (sem_destroy(&pCallbackData->sem))
    106    {
    107       ALOGE("Failed to destroy semaphore (errno=0x%08x)", errno);
    108    }
    109 
    110    /* Remove from active semaphore list */
    111    if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData))
    112    {
    113       ALOGE("Failed to remove semaphore from the list");
    114    }
    115 
    116 }
    117 
    118 void nfc_cb_data_releaseAll()
    119 {
    120    nfc_jni_callback_data* pCallbackData;
    121 
    122    while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData))
    123    {
    124       pCallbackData->status = NFCSTATUS_FAILED;
    125       sem_post(&pCallbackData->sem);
    126    }
    127 }
    128 
    129 int nfc_jni_cache_object(JNIEnv *e, const char *clsname,
    130    jobject *cached_obj)
    131 {
    132    ScopedLocalRef<jclass> cls(e, e->FindClass(clsname));
    133    if (cls.get() == NULL) {
    134       ALOGD("Find class error\n");
    135       return -1;
    136    }
    137 
    138    jmethodID ctor = e->GetMethodID(cls.get(), "<init>", "()V");
    139    ScopedLocalRef<jobject> obj(e, e->NewObject(cls.get(), ctor));
    140    if (obj.get() == NULL) {
    141       ALOGD("Create object error\n");
    142       return -1;
    143    }
    144 
    145    *cached_obj = e->NewGlobalRef(obj.get());
    146    if (*cached_obj == NULL) {
    147       ALOGD("Global ref error\n");
    148       return -1;
    149    }
    150 
    151    return 0;
    152 }
    153 
    154 
    155 struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o)
    156 {
    157    /* Retrieve native structure address */
    158    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    159    jfieldID f = e->GetFieldID(c.get(), "mNative", "I");
    160    return (struct nfc_jni_native_data*) e->GetIntField(o, f);
    161 }
    162 
    163 struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e)
    164 {
    165    return exported_nat;
    166 }
    167 
    168 static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL;
    169 
    170 nfc_jni_native_monitor_t* nfc_jni_init_monitor(void)
    171 {
    172 
    173    pthread_mutexattr_t recursive_attr;
    174 
    175    pthread_mutexattr_init(&recursive_attr);
    176    pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP);
    177 
    178    if(nfc_jni_native_monitor == NULL)
    179    {
    180       nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t));
    181    }
    182 
    183    if(nfc_jni_native_monitor != NULL)
    184    {
    185       memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t));
    186 
    187       if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1)
    188       {
    189          ALOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno);
    190          return NULL;
    191       }
    192 
    193       if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1)
    194       {
    195          ALOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno);
    196          return NULL;
    197       }
    198 
    199       if(!listInit(&nfc_jni_native_monitor->sem_list))
    200       {
    201          ALOGE("NFC Manager Semaphore List creation failed");
    202          return NULL;
    203       }
    204 
    205       LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head);
    206 
    207       if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1)
    208       {
    209          ALOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno);
    210          return NULL;
    211       }
    212 
    213       if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1)
    214       {
    215          ALOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno);
    216          return NULL;
    217       }
    218 
    219 }
    220 
    221    return nfc_jni_native_monitor;
    222 }
    223 
    224 nfc_jni_native_monitor_t* nfc_jni_get_monitor(void)
    225 {
    226    return nfc_jni_native_monitor;
    227 }
    228 
    229 
    230 phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o)
    231 {
    232    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    233    jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
    234    return e->GetIntField(o, f);
    235 }
    236 
    237 jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o)
    238 {
    239    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    240    jfieldID f = e->GetFieldID(c.get(), "mMode", "S");
    241    return e->GetShortField(o, f);
    242 }
    243 
    244 
    245 int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o)
    246 {
    247    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    248    jfieldID f = e->GetFieldID(c.get(), "mConnectedTechIndex", "I");
    249    return e->GetIntField(o, f);
    250 
    251 }
    252 
    253 jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o)
    254 {
    255    int connectedTech = -1;
    256 
    257    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
    258    jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o);
    259 
    260    if ((connectedTechIndex != -1) && (techTypes != NULL) &&
    261            (connectedTechIndex < e->GetArrayLength(techTypes))) {
    262        jint* technologies = e->GetIntArrayElements(techTypes, 0);
    263        if (technologies != NULL) {
    264            connectedTech = technologies[connectedTechIndex];
    265            e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT);
    266        }
    267    }
    268 
    269    return connectedTech;
    270 
    271 }
    272 
    273 jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o)
    274 {
    275    jint connectedLibNfcType = -1;
    276 
    277    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
    278    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    279    jfieldID f = e->GetFieldID(c.get(), "mTechLibNfcTypes", "[I");
    280    ScopedLocalRef<jintArray> libNfcTypes(e, (jintArray) e->GetObjectField(o, f));
    281 
    282    if ((connectedTechIndex != -1) && (libNfcTypes.get() != NULL) &&
    283            (connectedTechIndex < e->GetArrayLength(libNfcTypes.get()))) {
    284        jint* types = e->GetIntArrayElements(libNfcTypes.get(), 0);
    285        if (types != NULL) {
    286            connectedLibNfcType = types[connectedTechIndex];
    287            e->ReleaseIntArrayElements(libNfcTypes.get(), types, JNI_ABORT);
    288        }
    289    }
    290    return connectedLibNfcType;
    291 }
    292 
    293 phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o)
    294 {
    295    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    296    jfieldID f = e->GetFieldID(c.get(), "mConnectedHandle", "I");
    297    return e->GetIntField(o, f);
    298 }
    299 
    300 phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o)
    301 {
    302    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    303    jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
    304    return e->GetIntField(o, f);
    305 }
    306 
    307 jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o)
    308 {
    309    ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    310    jfieldID f = e->GetFieldID(c.get(), "mTechList","[I");
    311    return (jintArray) e->GetObjectField(o, f);
    312 }
    313 
    314 
    315 
    316 //Display status code
    317 const char* nfc_jni_get_status_name(NFCSTATUS status)
    318 {
    319    #define STATUS_ENTRY(status) { status, #status }
    320 
    321    struct status_entry {
    322       NFCSTATUS   code;
    323       const char  *name;
    324    };
    325 
    326    const struct status_entry sNameTable[] = {
    327       STATUS_ENTRY(NFCSTATUS_SUCCESS),
    328       STATUS_ENTRY(NFCSTATUS_FAILED),
    329       STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER),
    330       STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES),
    331       STATUS_ENTRY(NFCSTATUS_TARGET_LOST),
    332       STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE),
    333       STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS),
    334       STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED),
    335       STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED),
    336       STATUS_ENTRY(NFCSTATUS_SHUTDOWN),
    337       STATUS_ENTRY(NFCSTATUS_ABORTED),
    338       STATUS_ENTRY(NFCSTATUS_REJECTED ),
    339       STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED),
    340       STATUS_ENTRY(NFCSTATUS_PENDING),
    341       STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL),
    342       STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED),
    343       STATUS_ENTRY(NFCSTATUS_BUSY),
    344       STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED),
    345       STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS),
    346       STATUS_ENTRY(NFCSTATUS_DESELECTED),
    347       STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE),
    348       STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION),
    349       STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT),
    350       STATUS_ENTRY(NFCSTATUS_RF_ERROR),
    351       STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR),
    352       STATUS_ENTRY(NFCSTATUS_INVALID_STATE),
    353       STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED),
    354       STATUS_ENTRY(NFCSTATUS_RELEASED),
    355       STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED),
    356       STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE),
    357       STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED),
    358       STATUS_ENTRY(NFCSTATUS_READ_FAILED),
    359       STATUS_ENTRY(NFCSTATUS_WRITE_FAILED),
    360       STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT),
    361       STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED),
    362       STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH),
    363       STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT),
    364       STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE),
    365       STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR),
    366    };
    367 
    368    int i = sizeof(sNameTable)/sizeof(status_entry);
    369 
    370    while(i>0)
    371    {
    372       i--;
    373       if (sNameTable[i].code == PHNFCSTATUS(status))
    374       {
    375          return sNameTable[i].name;
    376       }
    377    }
    378 
    379    return "UNKNOWN";
    380 }
    381 
    382 int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize,
    383         int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) {
    384     bool found = false;
    385     for (int i = 0; i < listSize; i++) {
    386         if (techList[i] == techToAdd) {
    387             found = true;
    388             break;
    389         }
    390     }
    391     if (!found && listSize < maxListSize) {
    392         techList[listSize] = techToAdd;
    393         handleList[listSize] = handleToAdd;
    394         typeList[listSize] = typeToAdd;
    395         return listSize + 1;
    396     }
    397     else {
    398         return listSize;
    399     }
    400 }
    401 
    402 
    403 #define MAX_NUM_TECHNOLOGIES 32
    404 
    405 /*
    406  *  Utility to get a technology tree and a corresponding handle list from a detected tag.
    407  */
    408 void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList, uint8_t count,
    409                                  ScopedLocalRef<jintArray>* techList,
    410                                  ScopedLocalRef<jintArray>* handleList,
    411                                  ScopedLocalRef<jintArray>* libnfcTypeList)
    412 {
    413    int technologies[MAX_NUM_TECHNOLOGIES];
    414    int handles[MAX_NUM_TECHNOLOGIES];
    415    int libnfctypes[MAX_NUM_TECHNOLOGIES];
    416 
    417    int index = 0;
    418    // TODO: This counts from up to down because on multi-protocols, the
    419    // ISO handle is usually the second, and we prefer the ISO. Should implement
    420    // a method to find the "preferred handle order" and use that instead,
    421    // since we shouldn't have dependencies on the tech list ordering.
    422    for (int target = count - 1; target >= 0; target--) {
    423        int type = devList[target].psRemoteDevInfo->RemDevType;
    424        int handle = devList[target].hTargetDev;
    425        switch (type)
    426        {
    427           case phNfc_eISO14443_A_PICC:
    428           case phNfc_eISO14443_4A_PICC:
    429             {
    430               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    431                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
    432               break;
    433             }
    434           case phNfc_eISO14443_4B_PICC:
    435             {
    436               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    437                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
    438               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    439                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
    440             }break;
    441           case phNfc_eISO14443_3A_PICC:
    442             {
    443               index = addTechIfNeeded(technologies, handles, libnfctypes,
    444                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    445             }break;
    446           case phNfc_eISO14443_B_PICC:
    447             {
    448               // TODO a bug in libnfc will cause 14443-3B only cards
    449               // to be returned as this type as well, but these cards
    450               // are very rare. Hence assume it's -4B
    451               index = addTechIfNeeded(technologies, handles, libnfctypes,
    452                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
    453               index = addTechIfNeeded(technologies, handles, libnfctypes,
    454                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
    455             }break;
    456           case phNfc_eISO15693_PICC:
    457             {
    458               index = addTechIfNeeded(technologies, handles, libnfctypes,
    459                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type);
    460             }break;
    461           case phNfc_eMifare_PICC:
    462             {
    463               // We don't want to be too clever here; libnfc has already determined
    464               // it's a Mifare, so we only check for UL, for all other tags
    465               // we assume it's a mifare classic. This should make us more
    466               // future-proof.
    467               int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak;
    468               switch(sak)
    469               {
    470                 case 0x00:
    471                   // could be UL or UL-C
    472                   index = addTechIfNeeded(technologies, handles, libnfctypes,
    473                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type);
    474                   break;
    475                 default:
    476                   index = addTechIfNeeded(technologies, handles, libnfctypes,
    477                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type);
    478                   break;
    479               }
    480             }break;
    481           case phNfc_eFelica_PICC:
    482             {
    483               index = addTechIfNeeded(technologies, handles, libnfctypes,
    484                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type);
    485             }break;
    486           case phNfc_eJewel_PICC:
    487             {
    488               // Jewel represented as NfcA
    489               index = addTechIfNeeded(technologies, handles, libnfctypes,
    490                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    491             }break;
    492           default:
    493             {
    494               index = addTechIfNeeded(technologies, handles, libnfctypes,
    495                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type);
    496             }
    497         }
    498    }
    499 
    500    // Build the Java arrays
    501    if (techList != NULL) {
    502        techList->reset(e->NewIntArray(index));
    503        e->SetIntArrayRegion(techList->get(), 0, index, technologies);
    504    }
    505 
    506    if (handleList != NULL) {
    507        handleList->reset(e->NewIntArray(index));
    508        e->SetIntArrayRegion(handleList->get(), 0, index, handles);
    509    }
    510 
    511    if (libnfcTypeList != NULL) {
    512        libnfcTypeList->reset(e->NewIntArray(index));
    513        e->SetIntArrayRegion(libnfcTypeList->get(), 0, index, libnfctypes);
    514    }
    515 }
    516 
    517 } // namespace android
    518