【发布时间】:2017-03-20 09:40:21
【问题描述】:
我有一个 java 代码来打开 SqlCipher 数据库。我想从 JNI 调用 getWritableDatabase 函数来隐藏密码。
Java_com_company_pos_DbHelper_getWritableSqlite 方法 (sqlauth.cpp) 中的 SQLiteOpenHelper 类调用 getWritableDatabas 方法时出错,我的代码有什么问题?
DbHelper.java
public class DbHelper extends SQLiteOpenHelper {
//private final static String PASSWORD= "MyPassword"
private final static String TAG = "DbHelper";
private static SQLiteDatabase db = null;
/* This method works only password is not secure.
public void open() {
try {
//The password isn't hidden
db = getWritableDatabase(PASSWORD);
} catch (SQLiteException e) {
Log.e(TAG, e.getMessage());
}
}
*/
static {
System.loadLibrary("sqlauth");
}
private native SQLiteDatabase getWritableSqlite();
public void open() {
try {
//The password is hidden in jNI
db = getWritableSqlite();
} catch (SQLiteException e) {
Log.e(TAG, e.getMessage());
}
}
}
JNI
sqlauth.h
#include <jni.h>
#include <string.h>
#include <iostream>
#ifndef SQLAUTH_H
#define SQLAUTH_H
#endif
static char *CLS_SQLITEOPENHELPER = (char *) "net/sqlcipher/database/SQLiteOpenHelper";
static char *MID_GETWRITABLEDATABASE = (char *) "getWritableDatabase";
static char *SIG_GETWRITABLEDATABASE = (char *) "(Ljava/lang/String;)Lnet/sqlcipher/database/SQLiteDatabase;";
#ifdef __cplusplus
extern "C" {
#endif
JavaVM *_jvm;
jclass _clsSQLiteOpenHelper;
jobject _objGetWritableDatabase;
jmethodID _midGetWritableDatabase;
JNIEnv *getEnv();
jboolean tryCatch();
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved);
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved);
JNIEXPORT jobject JNICALL Java_com_company_pos_DbHelper_getWritableSqlite(JNIEnv *e, jobject obj);
#ifdef __cplusplus
}
#endif
sqlauth.cpp
#include "sqlauth.h"
#ifdef __cplusplus
extern "C" {
#endif
JNIEnv *getEnv() {
JNIEnv *env;
_jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
return env;
}
jboolean tryCatch() {
JNIEnv *env = getEnv();
if (env == NULL) {
return JNI_TRUE;
}
jthrowable ex = env->ExceptionOccurred();
if (ex) {
env->ExceptionClear();
return JNI_TRUE;
}
return JNI_FALSE;
}
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved) {
JNIEnv *env;
jclass clsDbHelper, clsSqliteDatabase, clsSQLiteOpenHelper;
_jvm = jvm;
if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6)) {
return JNI_ERR;
}
// SQLiteOpenHelper.java
clsSQLiteOpenHelper = env->FindClass(CLS_SQLITEOPENHELPER);
if (clsSQLiteOpenHelper == NULL) {
return JNI_ERR;
}
_clsSQLiteOpenHelper = (jclass) env->NewWeakGlobalRef(clsSQLiteOpenHelper);
if (_clsSQLiteOpenHelper == NULL) {
return JNI_ERR;
}
_midGetWritableDatabase = env->GetMethodID(_clsSQLiteOpenHelper, MID_GETWRITABLEDATABASE, SIG_GETWRITABLEDATABASE);
if (_midGetWritableDatabase == NULL) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *jvm, void *reserved) {
JNIEnv *env;
if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6)) {
return;
}
env->DeleteWeakGlobalRef(_clsSQLiteOpenHelper);
return;
}
JNIEXPORT jobject JNICALL
Java_com_company_pos_DbHelper_getWritableSqlite(JNIEnv *e, jobject obj) {
JNIEnv *env = getEnv();
if (env == NULL || obj == NULL) {
return NULL;
}
// Error in here when calling getWritableDatabase
// from net/sqlcipher/database/SQLiteOpenHelper
_objGetWritableDatabase = env->CallObjectMethod(_clsSQLiteOpenHelper, _midGetWritableDatabase, env->NewStringUTF("MyPassword"));
if (_objGetWritableDatabase == NULL || tryCatch()) {
return NULL; // Program stop in here.
}
return _objGetWritableDatabase;
}
#ifdef __cplusplus
}
#endif
SQLiteOpenHelper.class
public synchronized SQLiteDatabase getWritableDatabase(String password) {
return this.getWritableDatabase(password == null?null:password.toCharArray());
}
【问题讨论】:
-
_clsSQLiteOpenHelper是jclass,应该是jobject -
@pskink,将类的类型更改为对象时出现消息错误,如下所示“错误:(73, 48)错误:无法初始化'jclass'类型的参数(又名'_jclass *' ) 的左值类型为 'jobject' (aka '_jobject *')"
-
我不知道,基本上CallObjectMethod的第二个参数是对象实例而不是类实例
-
GetWritableDatabase 方法在 SQLiteOpenHelper.class 中。如何调用具有输出同步 SQLiteDatabase 的方法?我尝试使用 CallObjectMethod 但仍然出错。
-
Java_com_company_pos_DbHelper_getWritableSqlite(JNIEnv *e, jobject obj) {调用CallObjectMethod时应使用jobject obj作为第二个参数
标签: java android c++ java-native-interface sqlcipher