Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2014 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 #define LOG_TAG "Fingerprint-JNI"
     18 
     19 #include "JNIHelp.h"
     20 
     21 #include <android_runtime/AndroidRuntime.h>
     22 #include <android_runtime/Log.h>
     23 #include <hardware/hardware.h>
     24 #include <hardware/fingerprint.h>
     25 #include <utils/Log.h>
     26 
     27 #define FIND_CLASS(var, className) \
     28         var = env->FindClass(className); \
     29         LOG_FATAL_IF(! var, "Unable to find class " className); \
     30         var = jclass(env->NewGlobalRef(var));
     31 
     32 #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
     33         var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
     34         LOG_FATAL_IF(! var, "Unable to find static method" methodName);
     35 
     36 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
     37         var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
     38         LOG_FATAL_IF(! var, "Unable to find method" methodName);
     39 
     40 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
     41         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
     42         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
     43 
     44 namespace android {
     45 
     46 static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
     47 
     48 static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
     49 static struct {
     50     jclass clazz;
     51     jmethodID notify;
     52     jobject callbackObject;
     53 } gFingerprintServiceClassInfo;
     54 
     55 static struct {
     56     fingerprint_module_t const* module;
     57     fingerprint_device_t *device;
     58 } gContext;
     59 
     60 // Called by the HAL to notify us of fingerprint events
     61 static void hal_notify_callback(fingerprint_msg_t msg) {
     62     uint32_t arg1 = 0;
     63     uint32_t arg2 = 0;
     64     uint32_t arg3 = 0; // TODO
     65     switch (msg.type) {
     66         case FINGERPRINT_ERROR:
     67             arg1 = msg.data.error;
     68             break;
     69         case FINGERPRINT_ACQUIRED:
     70             arg1 = msg.data.acquired.acquired_info;
     71             break;
     72         case FINGERPRINT_PROCESSED:
     73             arg1 = msg.data.processed.id;
     74             break;
     75         case FINGERPRINT_TEMPLATE_ENROLLING:
     76             arg1 = msg.data.enroll.id;
     77             arg2 = msg.data.enroll.samples_remaining;
     78             arg3 = msg.data.enroll.data_collected_bmp;
     79             break;
     80         case FINGERPRINT_TEMPLATE_REMOVED:
     81             arg1 = msg.data.removed.id;
     82             break;
     83         default:
     84             ALOGE("fingerprint: invalid msg: %d", msg.type);
     85             return;
     86     }
     87     //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
     88 
     89 	// TODO: fix gross hack to attach JNI to calling thread
     90     JNIEnv* env = AndroidRuntime::getJNIEnv();
     91     if (env == NULL) {
     92         JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
     93         JavaVM* vm = AndroidRuntime::getJavaVM();
     94         int result = vm->AttachCurrentThread(&env, (void*) &args);
     95         if (result != JNI_OK) {
     96             ALOGE("Can't call JNI method: attach failed: %#x", result);
     97             return;
     98         }
     99     }
    100     env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
    101             gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
    102 }
    103 
    104 static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
    105     ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n");
    106     FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
    107     GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz,
    108            "notify", "(III)V");
    109     gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj);
    110 }
    111 
    112 static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
    113     ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
    114     int ret = gContext.device->enroll(gContext.device, timeout);
    115     return reinterpret_cast<jint>(ret);
    116 }
    117 
    118 static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
    119     ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n");
    120     int ret = gContext.device->enroll_cancel(gContext.device);
    121     return reinterpret_cast<jint>(ret);
    122 }
    123 
    124 static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
    125     ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
    126     int ret = gContext.device->remove(gContext.device, fingerprintId);
    127     return reinterpret_cast<jint>(ret);
    128 }
    129 
    130 static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
    131     ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
    132     int err;
    133     const hw_module_t *hw_module = NULL;
    134     if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
    135         ALOGE("Can't open fingerprint HW Module, error: %d", err);
    136         return 0;
    137     }
    138     if (NULL == hw_module) {
    139         ALOGE("No valid fingerprint module");
    140         return 0;
    141     }
    142 
    143     gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module);
    144 
    145     if (gContext.module->common.methods->open == NULL) {
    146         ALOGE("No valid open method");
    147         return 0;
    148     }
    149 
    150     hw_device_t *device = NULL;
    151 
    152     if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) {
    153         ALOGE("Can't open fingerprint methods, error: %d", err);
    154         return 0;
    155     }
    156 
    157     if (kVersion != device->version) {
    158         ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
    159         // return 0; // FIXME
    160     }
    161 
    162     gContext.device = reinterpret_cast<fingerprint_device_t*>(device);
    163     err = gContext.device->set_notify(gContext.device, hal_notify_callback);
    164     if (err < 0) {
    165         ALOGE("Failed in call to set_notify(), err=%d", err);
    166         return 0;
    167     }
    168 
    169     // Sanity check - remove
    170     if (gContext.device->notify != hal_notify_callback) {
    171         ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
    172     }
    173 
    174     ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
    175     return reinterpret_cast<jlong>(gContext.device);
    176 }
    177 
    178 static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
    179     return -ENOSYS; // TODO
    180 }
    181 
    182 // ----------------------------------------------------------------------------
    183 
    184 // TODO: clean up void methods
    185 static const JNINativeMethod g_methods[] = {
    186     { "nativeEnroll", "(I)I", (void*)nativeEnroll },
    187     { "nativeEnrollCancel", "()I", (void*)nativeEnroll },
    188     { "nativeRemove", "(I)I", (void*)nativeRemove },
    189     { "nativeOpenHal", "()I", (void*)nativeOpenHal },
    190     { "nativeCloseHal", "()I", (void*)nativeCloseHal },
    191     { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
    192 };
    193 
    194 int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
    195     FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
    196     GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify",
    197             "(III)V");
    198     int result = AndroidRuntime::registerNativeMethods(
    199         env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
    200     ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
    201     return result;
    202 }
    203 
    204 } // namespace android
    205