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