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#include <inttypes.h> 21 22#include <android_runtime/AndroidRuntime.h> 23#include <android_runtime/Log.h> 24#include <android_os_MessageQueue.h> 25#include <binder/IServiceManager.h> 26#include <utils/String16.h> 27#include <utils/Looper.h> 28#include <keystore/IKeystoreService.h> 29#include <keystore/keystore.h> // for error code 30 31#include <hardware/hardware.h> 32#include <hardware/fingerprint.h> 33#include <hardware/hw_auth_token.h> 34 35#include <utils/Log.h> 36#include "core_jni_helpers.h" 37 38 39namespace android { 40 41static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0); 42 43static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService"; 44static struct { 45 jclass clazz; 46 jmethodID notify; 47} gFingerprintServiceClassInfo; 48 49static struct { 50 fingerprint_module_t const* module; 51 fingerprint_device_t *device; 52} gContext; 53 54static sp<Looper> gLooper; 55static jobject gCallback; 56 57class CallbackHandler : public MessageHandler { 58 int type; 59 int arg1, arg2, arg3; 60public: 61 CallbackHandler(int type, int arg1, int arg2, int arg3) 62 : type(type), arg1(arg1), arg2(arg2), arg3(arg3) { } 63 64 virtual void handleMessage(const Message& message) { 65 //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2); 66 JNIEnv* env = AndroidRuntime::getJNIEnv(); 67 env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2, arg3); 68 } 69}; 70 71static void notifyKeystore(uint8_t *auth_token, size_t auth_token_length) { 72 if (auth_token != NULL && auth_token_length > 0) { 73 // TODO: cache service? 74 sp<IServiceManager> sm = defaultServiceManager(); 75 sp<IBinder> binder = sm->getService(String16("android.security.keystore")); 76 sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); 77 if (service != NULL) { 78 status_t ret = service->addAuthToken(auth_token, auth_token_length); 79 if (ret != ResponseCode::NO_ERROR) { 80 ALOGE("Falure sending auth token to KeyStore: %d", ret); 81 } 82 } else { 83 ALOGE("Unable to communicate with KeyStore"); 84 } 85 } 86} 87 88// Called by the HAL to notify us of fingerprint events 89static void hal_notify_callback(fingerprint_msg_t msg) { 90 uint32_t arg1 = 0; 91 uint32_t arg2 = 0; 92 uint32_t arg3 = 0; 93 switch (msg.type) { 94 case FINGERPRINT_ERROR: 95 arg1 = msg.data.error; 96 break; 97 case FINGERPRINT_ACQUIRED: 98 arg1 = msg.data.acquired.acquired_info; 99 break; 100 case FINGERPRINT_AUTHENTICATED: 101 arg1 = msg.data.authenticated.finger.fid; 102 arg2 = msg.data.authenticated.finger.gid; 103 if (arg1 != 0) { 104 notifyKeystore(reinterpret_cast<uint8_t *>(&msg.data.authenticated.hat), 105 sizeof(msg.data.authenticated.hat)); 106 } 107 break; 108 case FINGERPRINT_TEMPLATE_ENROLLING: 109 arg1 = msg.data.enroll.finger.fid; 110 arg2 = msg.data.enroll.finger.gid; 111 arg3 = msg.data.enroll.samples_remaining; 112 break; 113 case FINGERPRINT_TEMPLATE_REMOVED: 114 arg1 = msg.data.removed.finger.fid; 115 arg2 = msg.data.removed.finger.gid; 116 break; 117 default: 118 ALOGE("fingerprint: invalid msg: %d", msg.type); 119 return; 120 } 121 // This call potentially comes in on a thread not owned by us. Hand it off to our 122 // looper so it runs on our thread when calling back to FingerprintService. 123 // CallbackHandler object is reference-counted, so no cleanup necessary. 124 gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2, arg3), Message()); 125} 126 127static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callbackObj) { 128 ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n"); 129 gCallback = MakeGlobalRefOrDie(env, callbackObj); 130 gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper(); 131} 132 133static jint nativeEnroll(JNIEnv* env, jobject clazz, jbyteArray token, jint groupId, jint timeout) { 134 ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout); 135 const int tokenSize = env->GetArrayLength(token); 136 jbyte* tokenData = env->GetByteArrayElements(token, 0); 137 if (tokenSize != sizeof(hw_auth_token_t)) { 138 ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll() : invalid token size %d\n", tokenSize); 139 return -1; 140 } 141 int ret = gContext.device->enroll(gContext.device, 142 reinterpret_cast<const hw_auth_token_t*>(tokenData), groupId, timeout); 143 env->ReleaseByteArrayElements(token, tokenData, 0); 144 return reinterpret_cast<jint>(ret); 145} 146 147static jlong nativePreEnroll(JNIEnv* env, jobject clazz) { 148 uint64_t ret = gContext.device->pre_enroll(gContext.device); 149 // ALOG(LOG_VERBOSE, LOG_TAG, "nativePreEnroll(), result = %llx", ret); 150 return reinterpret_cast<jlong>((int64_t)ret); 151} 152 153static jint nativeStopEnrollment(JNIEnv* env, jobject clazz) { 154 ALOG(LOG_VERBOSE, LOG_TAG, "nativeStopEnrollment()\n"); 155 int ret = gContext.device->cancel(gContext.device); 156 return reinterpret_cast<jint>(ret); 157} 158 159static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint groupId) { 160 ALOG(LOG_VERBOSE, LOG_TAG, "nativeAuthenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId); 161 int ret = gContext.device->authenticate(gContext.device, sessionId, groupId); 162 return reinterpret_cast<jint>(ret); 163} 164 165static jint nativeStopAuthentication(JNIEnv* env, jobject clazz) { 166 ALOG(LOG_VERBOSE, LOG_TAG, "nativeStopAuthentication()\n"); 167 int ret = gContext.device->cancel(gContext.device); 168 return reinterpret_cast<jint>(ret); 169} 170 171static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerId, jint groupId) { 172 ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(fid=%d, gid=%d)\n", fingerId, groupId); 173 fingerprint_finger_id_t finger; 174 finger.fid = fingerId; 175 finger.gid = groupId; 176 int ret = gContext.device->remove(gContext.device, finger); 177 return reinterpret_cast<jint>(ret); 178} 179 180static jlong nativeGetAuthenticatorId(JNIEnv *, jobject clazz) { 181 return gContext.device->get_authenticator_id(gContext.device); 182} 183 184static jint nativeSetActiveGroup(JNIEnv *env, jobject clazz, jint gid, jbyteArray path) { 185 const int pathSize = env->GetArrayLength(path); 186 jbyte* pathData = env->GetByteArrayElements(path, 0); 187 if (pathSize >= PATH_MAX) { 188 ALOGE("Path name is too long\n"); 189 return -1; 190 } 191 char path_name[PATH_MAX] = {0}; 192 memcpy(path_name, pathData, pathSize); 193 ALOG(LOG_VERBOSE, LOG_TAG, "nativeSetActiveGroup() path: %s, gid: %d\n", path_name, gid); 194 int result = gContext.device->set_active_group(gContext.device, gid, path_name); 195 env->ReleaseByteArrayElements(path, pathData, 0); 196 return result; 197} 198 199static jint nativeOpenHal(JNIEnv* env, jobject clazz) { 200 ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n"); 201 int err; 202 const hw_module_t *hw_module = NULL; 203 if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) { 204 ALOGE("Can't open fingerprint HW Module, error: %d", err); 205 return 0; 206 } 207 if (NULL == hw_module) { 208 ALOGE("No valid fingerprint module"); 209 return 0; 210 } 211 212 gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module); 213 214 if (gContext.module->common.methods->open == NULL) { 215 ALOGE("No valid open method"); 216 return 0; 217 } 218 219 hw_device_t *device = NULL; 220 221 if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) { 222 ALOGE("Can't open fingerprint methods, error: %d", err); 223 return 0; 224 } 225 226 if (kVersion != device->version) { 227 ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version); 228 // return 0; // FIXME 229 } 230 231 gContext.device = reinterpret_cast<fingerprint_device_t*>(device); 232 err = gContext.device->set_notify(gContext.device, hal_notify_callback); 233 if (err < 0) { 234 ALOGE("Failed in call to set_notify(), err=%d", err); 235 return 0; 236 } 237 238 // Sanity check - remove 239 if (gContext.device->notify != hal_notify_callback) { 240 ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback); 241 } 242 243 ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized"); 244 return reinterpret_cast<jlong>(gContext.device); 245} 246 247static jint nativeCloseHal(JNIEnv* env, jobject clazz) { 248 return -ENOSYS; // TODO 249} 250 251 252// ---------------------------------------------------------------------------- 253 254 255// TODO: clean up void methods 256static const JNINativeMethod g_methods[] = { 257 { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate }, 258 { "nativeStopAuthentication", "()I", (void*)nativeStopAuthentication }, 259 { "nativeEnroll", "([BII)I", (void*)nativeEnroll }, 260 { "nativeSetActiveGroup", "(I[B)I", (void*)nativeSetActiveGroup }, 261 { "nativePreEnroll", "()J", (void*)nativePreEnroll }, 262 { "nativeStopEnrollment", "()I", (void*)nativeStopEnrollment }, 263 { "nativeRemove", "(II)I", (void*)nativeRemove }, 264 { "nativeGetAuthenticatorId", "()J", (void*)nativeGetAuthenticatorId }, 265 { "nativeOpenHal", "()I", (void*)nativeOpenHal }, 266 { "nativeCloseHal", "()I", (void*)nativeCloseHal }, 267 { "nativeInit","(Landroid/os/MessageQueue;" 268 "Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit } 269}; 270 271int register_android_server_fingerprint_FingerprintService(JNIEnv* env) { 272 jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE); 273 gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); 274 gFingerprintServiceClassInfo.notify = 275 GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(IIII)V"); 276 int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods)); 277 ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n"); 278 return result; 279} 280 281} // namespace android 282