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 <nativehelper/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 
     39 namespace android {
     40 
     41 static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
     42 
     43 static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
     44 static struct {
     45     jclass clazz;
     46     jmethodID notify;
     47 } gFingerprintServiceClassInfo;
     48 
     49 static struct {
     50     fingerprint_module_t const* module;
     51     fingerprint_device_t *device;
     52 } gContext;
     53 
     54 static sp<Looper> gLooper;
     55 static jobject gCallback;
     56 
     57 class CallbackHandler : public MessageHandler {
     58     int type;
     59     int arg1, arg2, arg3;
     60 public:
     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 
     71 static 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
     89 static 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 
    127 static 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 
    133 static 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 
    147 static 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 
    153 static 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 
    159 static 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 
    165 static 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 
    171 static 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 
    180 static jlong nativeGetAuthenticatorId(JNIEnv *, jobject clazz) {
    181     return gContext.device->get_authenticator_id(gContext.device);
    182 }
    183 
    184 static 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 
    199 static 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 
    247 static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
    248     return -ENOSYS; // TODO
    249 }
    250 
    251 
    252 // ----------------------------------------------------------------------------
    253 
    254 
    255 // TODO: clean up void methods
    256 static 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 
    271 int 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