From 2174bfdcfd4dbd8ea6e1a60802425b1ab90390a3 Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Fri, 5 Sep 2025 16:53:51 -0400 Subject: [PATCH 1/4] Updates include path to allow architecture-specific includes --- sqlcipher/src/main/jni/sqlcipher/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcipher/src/main/jni/sqlcipher/Android.mk b/sqlcipher/src/main/jni/sqlcipher/Android.mk index fe08844..b5f5105 100644 --- a/sqlcipher/src/main/jni/sqlcipher/Android.mk +++ b/sqlcipher/src/main/jni/sqlcipher/Android.mk @@ -33,7 +33,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES += sqlite3.c -LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/nativehelper/ $(LOCAL_PATH)/android-libs/include/ +LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/nativehelper/ $(LOCAL_PATH)/android-libs/include/ $(LOCAL_PATH)/android-libs/include/$(TARGET_ARCH_ABI) LOCAL_MODULE:= libsqlcipher LOCAL_LDLIBS += -ldl -llog From 384f060a5305a321b7fb4917b18187effd924616 Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Fri, 5 Sep 2025 17:00:16 -0400 Subject: [PATCH 2/4] Sets sqlcipher temp directory path to application cacheDir --- .../android_database_SQLiteConnection.cpp | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp b/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp index 2ae8e81..6504b26 100644 --- a/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp +++ b/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp @@ -921,17 +921,61 @@ extern int register_android_database_CursorWindow(JNIEnv *env); } // namespace android +void setEnvarToCacheDirectory(JNIEnv* env, const char *envar) { + jclass activity = NULL, context = NULL, file = NULL; + jmethodID getCurrentApp = NULL, getCacheDir = NULL, getAbsolutePath = NULL; + jobject app = NULL, cache = NULL; + jstring path = NULL; + const char *pathUtf8 = NULL, *tmpdir = getenv(envar); + + /* check if SQLCIPHER_TMP is already set externally by the application (i.e. an override), and return immediately if it is */ + if(tmpdir && strlen(tmpdir) > 0) { + return; + } + + /* call ActivityThread.currentApplication().getCacheDir().getAbsolutePath() and set it to SQLCIPHER_TMP*/ + if ( + (activity = env->FindClass("android/app/ActivityThread")) + && (context = env->FindClass("android/content/Context")) + && (file = env->FindClass("java/io/File")) + && (getCurrentApp = env->GetStaticMethodID(activity, "currentApplication", "()Landroid/app/Application;")) + && (getCacheDir = env->GetMethodID(context, "getCacheDir", "()Ljava/io/File;")) + && (getAbsolutePath = env->GetMethodID(file, "getAbsolutePath", "()Ljava/lang/String;")) + && (app = env->CallStaticObjectMethod(activity, getCurrentApp)) + && (cache = env->CallObjectMethod(app, getCacheDir)) + && (path = (jstring) env->CallObjectMethod(cache, getAbsolutePath)) + && (pathUtf8 = env->GetStringUTFChars(path, NULL)) + ) { + setenv(envar, pathUtf8, 1); + } else { + ALOGE("%s unable to obtain cache directory from JNIEnv", __func__); + } + + /* cleanup */ + if(pathUtf8) env->ReleaseStringUTFChars(path, pathUtf8); + if(path) env->DeleteLocalRef(path); + if(cache) env->DeleteLocalRef(cache); + if(app) env->DeleteLocalRef(app); + if(file) env->DeleteLocalRef(file); + if(context) env->DeleteLocalRef(context); + if(activity) env->DeleteLocalRef(activity); +} + + extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env = 0; android::gpJavaVM = vm; vm->GetEnv((void**)&env, JNI_VERSION_1_4); + setEnvarToCacheDirectory(env, "SQLCIPHER_TMP"); + android::register_android_database_SQLiteConnection(env); android::register_android_database_SQLiteDebug(env); android::register_android_database_SQLiteGlobal(env); android::register_android_database_CursorWindow(env); + return JNI_VERSION_1_4; } From d60f1f0823b95f2956bcdbc616ce55ff5472a5c8 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 26 Sep 2025 10:23:53 -0500 Subject: [PATCH 3/4] Update test to 4.10.0 --- .../zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java index 1ed9111..df330ea 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java @@ -17,6 +17,6 @@ public void shouldExtractLibraryCipherVersion() { cipherVersion = cursor.getString(0); cursor.close(); } - assertThat(cipherVersion, containsString("4.6.1")); + assertThat(cipherVersion, containsString("4.10.0")); } } From 698c861f6fed9444d8cf813fc07a5db18d26a358 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Fri, 26 Sep 2025 10:27:59 -0500 Subject: [PATCH 4/4] Use sqlite3_close_v2 instead of sqlite3_close for improved cleanup --- .../sqlcipher/android_database_SQLiteConnection.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp b/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp index 6504b26..f0eab3c 100644 --- a/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp +++ b/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp @@ -211,14 +211,14 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla err = sqlite3_create_collation(db, "localized", SQLITE_UTF8, 0, coll_localized); if (err != SQLITE_OK) { throw_sqlite3_exception_errcode(env, err, "Could not register collation"); - sqlite3_close(db); + sqlite3_close_v2(db); return 0; } // Check that the database is really read/write when that is what we asked for. if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) { throw_sqlite3_exception(env, db, "Could not open the database in read/write mode."); - sqlite3_close(db); + sqlite3_close_v2(db); return 0; } @@ -226,7 +226,7 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS); if (err != SQLITE_OK) { throw_sqlite3_exception(env, db, "Could not set busy timeout"); - sqlite3_close(db); + sqlite3_close_v2(db); return 0; } @@ -253,10 +253,10 @@ static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) { if (connection) { ALOGV("Closing connection %p", connection->db); - int err = sqlite3_close(connection->db); + int err = sqlite3_close_v2(connection->db); if (err != SQLITE_OK) { // This can happen if sub-objects aren't closed first. Make sure the caller knows. - ALOGE("sqlite3_close(%p) failed: %d", connection->db, err); + ALOGE("sqlite3_close_v2(%p) failed: %d", connection->db, err); throw_sqlite3_exception(env, connection->db, "Count not close db."); return; } @@ -967,9 +967,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { android::gpJavaVM = vm; vm->GetEnv((void**)&env, JNI_VERSION_1_4); - setEnvarToCacheDirectory(env, "SQLCIPHER_TMP"); - android::register_android_database_SQLiteConnection(env); android::register_android_database_SQLiteDebug(env); android::register_android_database_SQLiteGlobal(env);