/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Fingerprint-JNI" #include "JNIHelp.h" #include #include #include #include #include #include #include #include "core_jni_helpers.h" namespace android { static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0); static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService"; static struct { jclass clazz; jmethodID notify; } gFingerprintServiceClassInfo; static struct { fingerprint_module_t const* module; fingerprint_device_t *device; } gContext; static sp gLooper; static jobject gCallback; class CallbackHandler : public MessageHandler { int type; int arg1, arg2; public: CallbackHandler(int type, int arg1, int arg2) : type(type), arg1(arg1), arg2(arg2) { } virtual void handleMessage(const Message& message) { //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2); JNIEnv* env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2); } }; // Called by the HAL to notify us of fingerprint events static void hal_notify_callback(fingerprint_msg_t msg) { uint32_t arg1 = 0; uint32_t arg2 = 0; switch (msg.type) { case FINGERPRINT_ERROR: arg1 = msg.data.error; break; case FINGERPRINT_ACQUIRED: arg1 = msg.data.acquired.acquired_info; break; case FINGERPRINT_PROCESSED: arg1 = msg.data.processed.finger.fid; break; case FINGERPRINT_TEMPLATE_ENROLLING: arg1 = msg.data.enroll.finger.fid; arg2 = msg.data.enroll.samples_remaining; break; case FINGERPRINT_TEMPLATE_REMOVED: arg1 = msg.data.removed.finger.fid; break; default: ALOGE("fingerprint: invalid msg: %d", msg.type); return; } // This call potentially comes in on a thread not owned by us. Hand it off to our // looper so it runs on our thread when calling back to FingerprintService. // CallbackHandler object is reference-counted, so no cleanup necessary. gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2), Message()); } static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callbackObj) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n"); gCallback = MakeGlobalRefOrDie(env, callbackObj); gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper(); } static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n"); int ret = gContext.device->enroll(gContext.device, 0, timeout); return reinterpret_cast(ret); } static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n"); int ret = gContext.device->enroll_cancel(gContext.device); return reinterpret_cast(ret); } static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId); fingerprint_finger_id_t finger; finger.gid = 0; finger.fid = fingerprintId; int ret = gContext.device->remove(gContext.device, finger); return reinterpret_cast(ret); } static jint nativeOpenHal(JNIEnv* env, jobject clazz) { ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n"); int err; const hw_module_t *hw_module = NULL; if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) { ALOGE("Can't open fingerprint HW Module, error: %d", err); return 0; } if (NULL == hw_module) { ALOGE("No valid fingerprint module"); return 0; } gContext.module = reinterpret_cast(hw_module); if (gContext.module->common.methods->open == NULL) { ALOGE("No valid open method"); return 0; } hw_device_t *device = NULL; if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) { ALOGE("Can't open fingerprint methods, error: %d", err); return 0; } if (kVersion != device->version) { ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version); // return 0; // FIXME } gContext.device = reinterpret_cast(device); err = gContext.device->set_notify(gContext.device, hal_notify_callback); if (err < 0) { ALOGE("Failed in call to set_notify(), err=%d", err); return 0; } // Sanity check - remove if (gContext.device->notify != hal_notify_callback) { ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback); } ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized"); return reinterpret_cast(gContext.device); } static jint nativeCloseHal(JNIEnv* env, jobject clazz) { return -ENOSYS; // TODO } // ---------------------------------------------------------------------------- // TODO: clean up void methods static const JNINativeMethod g_methods[] = { { "nativeEnroll", "(I)I", (void*)nativeEnroll }, { "nativeEnrollCancel", "()I", (void*)nativeEnrollCancel }, { "nativeRemove", "(I)I", (void*)nativeRemove }, { "nativeOpenHal", "()I", (void*)nativeOpenHal }, { "nativeCloseHal", "()I", (void*)nativeCloseHal }, { "nativeInit","(Landroid/os/MessageQueue;" "Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit } }; int register_android_server_fingerprint_FingerprintService(JNIEnv* env) { jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE); gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); gFingerprintServiceClassInfo.notify = GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(III)V"); int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods)); ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n"); return result; } } // namespace android