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