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
hal_notify_callback(fingerprint_msg_t msg)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
nativeInit(JNIEnv * env,jobject clazz,jobject callbackObj)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
nativeEnroll(JNIEnv * env,jobject clazz,jint timeout)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
nativeEnrollCancel(JNIEnv * env,jobject clazz)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
nativeRemove(JNIEnv * env,jobject clazz,jint fingerprintId)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
nativeOpenHal(JNIEnv * env,jobject clazz)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
nativeCloseHal(JNIEnv * env,jobject clazz)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
register_android_server_fingerprint_FingerprintService(JNIEnv * env)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