Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 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 "SQLiteConnection"
     18 
     19 #include <jni.h>
     20 #include <nativehelper/JNIHelp.h>
     21 #include <android_runtime/AndroidRuntime.h>
     22 #include <android_runtime/Log.h>
     23 
     24 #include <utils/Log.h>
     25 #include <utils/String8.h>
     26 #include <utils/String16.h>
     27 #include <cutils/ashmem.h>
     28 #include <sys/mman.h>
     29 
     30 #include <string.h>
     31 #include <unistd.h>
     32 
     33 #include <androidfw/CursorWindow.h>
     34 
     35 #include <sqlite3.h>
     36 #include <sqlite3_android.h>
     37 
     38 #include "android_database_SQLiteCommon.h"
     39 
     40 #include "core_jni_helpers.h"
     41 
     42 // Set to 1 to use UTF16 storage for localized indexes.
     43 #define UTF16_STORAGE 0
     44 
     45 namespace android {
     46 
     47 /* Busy timeout in milliseconds.
     48  * If another connection (possibly in another process) has the database locked for
     49  * longer than this amount of time then SQLite will generate a SQLITE_BUSY error.
     50  * The SQLITE_BUSY error is then raised as a SQLiteDatabaseLockedException.
     51  *
     52  * In ordinary usage, busy timeouts are quite rare.  Most databases only ever
     53  * have a single open connection at a time unless they are using WAL.  When using
     54  * WAL, a timeout could occur if one connection is busy performing an auto-checkpoint
     55  * operation.  The busy timeout needs to be long enough to tolerate slow I/O write
     56  * operations but not so long as to cause the application to hang indefinitely if
     57  * there is a problem acquiring a database lock.
     58  */
     59 static const int BUSY_TIMEOUT_MS = 2500;
     60 
     61 static struct {
     62     jfieldID name;
     63     jfieldID numArgs;
     64     jmethodID dispatchCallback;
     65 } gSQLiteCustomFunctionClassInfo;
     66 
     67 static struct {
     68     jclass clazz;
     69 } gStringClassInfo;
     70 
     71 struct SQLiteConnection {
     72     // Open flags.
     73     // Must be kept in sync with the constants defined in SQLiteDatabase.java.
     74     enum {
     75         OPEN_READWRITE          = 0x00000000,
     76         OPEN_READONLY           = 0x00000001,
     77         OPEN_READ_MASK          = 0x00000001,
     78         NO_LOCALIZED_COLLATORS  = 0x00000010,
     79         CREATE_IF_NECESSARY     = 0x10000000,
     80     };
     81 
     82     sqlite3* const db;
     83     const int openFlags;
     84     const String8 path;
     85     const String8 label;
     86 
     87     volatile bool canceled;
     88 
     89     SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
     90         db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
     91 };
     92 
     93 // Called each time a statement begins execution, when tracing is enabled.
     94 static void sqliteTraceCallback(void *data, const char *sql) {
     95     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
     96     ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n",
     97             connection->label.string(), sql);
     98 }
     99 
    100 // Called each time a statement finishes execution, when profiling is enabled.
    101 static void sqliteProfileCallback(void *data, const char *sql, sqlite3_uint64 tm) {
    102     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
    103     ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n",
    104             connection->label.string(), sql, tm * 0.000001f);
    105 }
    106 
    107 // Called after each SQLite VM instruction when cancelation is enabled.
    108 static int sqliteProgressHandlerCallback(void* data) {
    109     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
    110     return connection->canceled;
    111 }
    112 
    113 
    114 static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
    115         jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
    116         jint lookasideCnt) {
    117     int sqliteFlags;
    118     if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
    119         sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    120     } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
    121         sqliteFlags = SQLITE_OPEN_READONLY;
    122     } else {
    123         sqliteFlags = SQLITE_OPEN_READWRITE;
    124     }
    125 
    126     const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
    127     String8 path(pathChars);
    128     env->ReleaseStringUTFChars(pathStr, pathChars);
    129 
    130     const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
    131     String8 label(labelChars);
    132     env->ReleaseStringUTFChars(labelStr, labelChars);
    133 
    134     sqlite3* db;
    135     int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
    136     if (err != SQLITE_OK) {
    137         throw_sqlite3_exception_errcode(env, err, "Could not open database");
    138         return 0;
    139     }
    140 
    141     if (lookasideSz >= 0 && lookasideCnt >= 0) {
    142         int err = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL, lookasideSz, lookasideCnt);
    143         if (err != SQLITE_OK) {
    144             ALOGE("sqlite3_db_config(..., %d, %d) failed: %d", lookasideSz, lookasideCnt, err);
    145             throw_sqlite3_exception(env, db, "Cannot set lookaside");
    146             sqlite3_close(db);
    147             return 0;
    148         }
    149     }
    150 
    151     // Check that the database is really read/write when that is what we asked for.
    152     if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
    153         throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
    154         sqlite3_close(db);
    155         return 0;
    156     }
    157 
    158     // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
    159     err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
    160     if (err != SQLITE_OK) {
    161         throw_sqlite3_exception(env, db, "Could not set busy timeout");
    162         sqlite3_close(db);
    163         return 0;
    164     }
    165 
    166     // Register custom Android functions.
    167     err = register_android_functions(db, UTF16_STORAGE);
    168     if (err) {
    169         throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
    170         sqlite3_close(db);
    171         return 0;
    172     }
    173 
    174     // Create wrapper object.
    175     SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);
    176 
    177     // Enable tracing and profiling if requested.
    178     if (enableTrace) {
    179         sqlite3_trace(db, &sqliteTraceCallback, connection);
    180     }
    181     if (enableProfile) {
    182         sqlite3_profile(db, &sqliteProfileCallback, connection);
    183     }
    184 
    185     ALOGV("Opened connection %p with label '%s'", db, label.string());
    186     return reinterpret_cast<jlong>(connection);
    187 }
    188 
    189 static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) {
    190     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    191 
    192     if (connection) {
    193         ALOGV("Closing connection %p", connection->db);
    194         int err = sqlite3_close(connection->db);
    195         if (err != SQLITE_OK) {
    196             // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
    197             ALOGE("sqlite3_close(%p) failed: %d", connection->db, err);
    198             throw_sqlite3_exception(env, connection->db, "Count not close db.");
    199             return;
    200         }
    201 
    202         delete connection;
    203     }
    204 }
    205 
    206 // Called each time a custom function is evaluated.
    207 static void sqliteCustomFunctionCallback(sqlite3_context *context,
    208         int argc, sqlite3_value **argv) {
    209     JNIEnv* env = AndroidRuntime::getJNIEnv();
    210 
    211     // Get the callback function object.
    212     // Create a new local reference to it in case the callback tries to do something
    213     // dumb like unregister the function (thereby destroying the global ref) while it is running.
    214     jobject functionObjGlobal = reinterpret_cast<jobject>(sqlite3_user_data(context));
    215     jobject functionObj = env->NewLocalRef(functionObjGlobal);
    216 
    217     jobjectArray argsArray = env->NewObjectArray(argc, gStringClassInfo.clazz, NULL);
    218     if (argsArray) {
    219         for (int i = 0; i < argc; i++) {
    220             const jchar* arg = static_cast<const jchar*>(sqlite3_value_text16(argv[i]));
    221             if (!arg) {
    222                 ALOGW("NULL argument in custom_function_callback.  This should not happen.");
    223             } else {
    224                 size_t argLen = sqlite3_value_bytes16(argv[i]) / sizeof(jchar);
    225                 jstring argStr = env->NewString(arg, argLen);
    226                 if (!argStr) {
    227                     goto error; // out of memory error
    228                 }
    229                 env->SetObjectArrayElement(argsArray, i, argStr);
    230                 env->DeleteLocalRef(argStr);
    231             }
    232         }
    233 
    234         // TODO: Support functions that return values.
    235         env->CallVoidMethod(functionObj,
    236                 gSQLiteCustomFunctionClassInfo.dispatchCallback, argsArray);
    237 
    238 error:
    239         env->DeleteLocalRef(argsArray);
    240     }
    241 
    242     env->DeleteLocalRef(functionObj);
    243 
    244     if (env->ExceptionCheck()) {
    245         ALOGE("An exception was thrown by custom SQLite function.");
    246         LOGE_EX(env);
    247         env->ExceptionClear();
    248     }
    249 }
    250 
    251 // Called when a custom function is destroyed.
    252 static void sqliteCustomFunctionDestructor(void* data) {
    253     jobject functionObjGlobal = reinterpret_cast<jobject>(data);
    254 
    255     JNIEnv* env = AndroidRuntime::getJNIEnv();
    256     env->DeleteGlobalRef(functionObjGlobal);
    257 }
    258 
    259 static void nativeRegisterCustomFunction(JNIEnv* env, jclass clazz, jlong connectionPtr,
    260         jobject functionObj) {
    261     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    262 
    263     jstring nameStr = jstring(env->GetObjectField(
    264             functionObj, gSQLiteCustomFunctionClassInfo.name));
    265     jint numArgs = env->GetIntField(functionObj, gSQLiteCustomFunctionClassInfo.numArgs);
    266 
    267     jobject functionObjGlobal = env->NewGlobalRef(functionObj);
    268 
    269     const char* name = env->GetStringUTFChars(nameStr, NULL);
    270     int err = sqlite3_create_function_v2(connection->db, name, numArgs, SQLITE_UTF16,
    271             reinterpret_cast<void*>(functionObjGlobal),
    272             &sqliteCustomFunctionCallback, NULL, NULL, &sqliteCustomFunctionDestructor);
    273     env->ReleaseStringUTFChars(nameStr, name);
    274 
    275     if (err != SQLITE_OK) {
    276         ALOGE("sqlite3_create_function returned %d", err);
    277         env->DeleteGlobalRef(functionObjGlobal);
    278         throw_sqlite3_exception(env, connection->db);
    279         return;
    280     }
    281 }
    282 
    283 static void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jlong connectionPtr,
    284         jstring localeStr) {
    285     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    286 
    287     const char* locale = env->GetStringUTFChars(localeStr, NULL);
    288     int err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
    289     env->ReleaseStringUTFChars(localeStr, locale);
    290 
    291     if (err != SQLITE_OK) {
    292         throw_sqlite3_exception(env, connection->db);
    293     }
    294 }
    295 
    296 static jlong nativePrepareStatement(JNIEnv* env, jclass clazz, jlong connectionPtr,
    297         jstring sqlString) {
    298     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    299 
    300     jsize sqlLength = env->GetStringLength(sqlString);
    301     const jchar* sql = env->GetStringCritical(sqlString, NULL);
    302     sqlite3_stmt* statement;
    303     int err = sqlite3_prepare16_v2(connection->db,
    304             sql, sqlLength * sizeof(jchar), &statement, NULL);
    305     env->ReleaseStringCritical(sqlString, sql);
    306 
    307     if (err != SQLITE_OK) {
    308         // Error messages like 'near ")": syntax error' are not
    309         // always helpful enough, so construct an error string that
    310         // includes the query itself.
    311         const char *query = env->GetStringUTFChars(sqlString, NULL);
    312         char *message = (char*) malloc(strlen(query) + 50);
    313         if (message) {
    314             strcpy(message, ", while compiling: "); // less than 50 chars
    315             strcat(message, query);
    316         }
    317         env->ReleaseStringUTFChars(sqlString, query);
    318         throw_sqlite3_exception(env, connection->db, message);
    319         free(message);
    320         return 0;
    321     }
    322 
    323     ALOGV("Prepared statement %p on connection %p", statement, connection->db);
    324     return reinterpret_cast<jlong>(statement);
    325 }
    326 
    327 static void nativeFinalizeStatement(JNIEnv* env, jclass clazz, jlong connectionPtr,
    328         jlong statementPtr) {
    329     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    330     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    331 
    332     // We ignore the result of sqlite3_finalize because it is really telling us about
    333     // whether any errors occurred while executing the statement.  The statement itself
    334     // is always finalized regardless.
    335     ALOGV("Finalized statement %p on connection %p", statement, connection->db);
    336     sqlite3_finalize(statement);
    337 }
    338 
    339 static jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
    340         jlong statementPtr) {
    341     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    342 
    343     return sqlite3_bind_parameter_count(statement);
    344 }
    345 
    346 static jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jlong connectionPtr,
    347         jlong statementPtr) {
    348     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    349 
    350     return sqlite3_stmt_readonly(statement) != 0;
    351 }
    352 
    353 static jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
    354         jlong statementPtr) {
    355     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    356 
    357     return sqlite3_column_count(statement);
    358 }
    359 
    360 static jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jlong connectionPtr,
    361         jlong statementPtr, jint index) {
    362     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    363 
    364     const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(statement, index));
    365     if (name) {
    366         size_t length = 0;
    367         while (name[length]) {
    368             length += 1;
    369         }
    370         return env->NewString(name, length);
    371     }
    372     return NULL;
    373 }
    374 
    375 static void nativeBindNull(JNIEnv* env, jclass clazz, jlong connectionPtr,
    376         jlong statementPtr, jint index) {
    377     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    378     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    379 
    380     int err = sqlite3_bind_null(statement, index);
    381     if (err != SQLITE_OK) {
    382         throw_sqlite3_exception(env, connection->db, NULL);
    383     }
    384 }
    385 
    386 static void nativeBindLong(JNIEnv* env, jclass clazz, jlong connectionPtr,
    387         jlong statementPtr, jint index, jlong value) {
    388     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    389     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    390 
    391     int err = sqlite3_bind_int64(statement, index, value);
    392     if (err != SQLITE_OK) {
    393         throw_sqlite3_exception(env, connection->db, NULL);
    394     }
    395 }
    396 
    397 static void nativeBindDouble(JNIEnv* env, jclass clazz, jlong connectionPtr,
    398         jlong statementPtr, jint index, jdouble value) {
    399     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    400     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    401 
    402     int err = sqlite3_bind_double(statement, index, value);
    403     if (err != SQLITE_OK) {
    404         throw_sqlite3_exception(env, connection->db, NULL);
    405     }
    406 }
    407 
    408 static void nativeBindString(JNIEnv* env, jclass clazz, jlong connectionPtr,
    409         jlong statementPtr, jint index, jstring valueString) {
    410     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    411     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    412 
    413     jsize valueLength = env->GetStringLength(valueString);
    414     const jchar* value = env->GetStringCritical(valueString, NULL);
    415     int err = sqlite3_bind_text16(statement, index, value, valueLength * sizeof(jchar),
    416             SQLITE_TRANSIENT);
    417     env->ReleaseStringCritical(valueString, value);
    418     if (err != SQLITE_OK) {
    419         throw_sqlite3_exception(env, connection->db, NULL);
    420     }
    421 }
    422 
    423 static void nativeBindBlob(JNIEnv* env, jclass clazz, jlong connectionPtr,
    424         jlong statementPtr, jint index, jbyteArray valueArray) {
    425     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    426     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    427 
    428     jsize valueLength = env->GetArrayLength(valueArray);
    429     jbyte* value = static_cast<jbyte*>(env->GetPrimitiveArrayCritical(valueArray, NULL));
    430     int err = sqlite3_bind_blob(statement, index, value, valueLength, SQLITE_TRANSIENT);
    431     env->ReleasePrimitiveArrayCritical(valueArray, value, JNI_ABORT);
    432     if (err != SQLITE_OK) {
    433         throw_sqlite3_exception(env, connection->db, NULL);
    434     }
    435 }
    436 
    437 static void nativeResetStatementAndClearBindings(JNIEnv* env, jclass clazz, jlong connectionPtr,
    438         jlong statementPtr) {
    439     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    440     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    441 
    442     int err = sqlite3_reset(statement);
    443     if (err == SQLITE_OK) {
    444         err = sqlite3_clear_bindings(statement);
    445     }
    446     if (err != SQLITE_OK) {
    447         throw_sqlite3_exception(env, connection->db, NULL);
    448     }
    449 }
    450 
    451 static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
    452     int err = sqlite3_step(statement);
    453     if (err == SQLITE_ROW) {
    454         throw_sqlite3_exception(env,
    455                 "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
    456     } else if (err != SQLITE_DONE) {
    457         throw_sqlite3_exception(env, connection->db);
    458     }
    459     return err;
    460 }
    461 
    462 static void nativeExecute(JNIEnv* env, jclass clazz, jlong connectionPtr,
    463         jlong statementPtr) {
    464     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    465     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    466 
    467     executeNonQuery(env, connection, statement);
    468 }
    469 
    470 static jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz,
    471         jlong connectionPtr, jlong statementPtr) {
    472     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    473     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    474 
    475     int err = executeNonQuery(env, connection, statement);
    476     return err == SQLITE_DONE ? sqlite3_changes(connection->db) : -1;
    477 }
    478 
    479 static jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz,
    480         jlong connectionPtr, jlong statementPtr) {
    481     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    482     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    483 
    484     int err = executeNonQuery(env, connection, statement);
    485     return err == SQLITE_DONE && sqlite3_changes(connection->db) > 0
    486             ? sqlite3_last_insert_rowid(connection->db) : -1;
    487 }
    488 
    489 static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
    490     int err = sqlite3_step(statement);
    491     if (err != SQLITE_ROW) {
    492         throw_sqlite3_exception(env, connection->db);
    493     }
    494     return err;
    495 }
    496 
    497 static jlong nativeExecuteForLong(JNIEnv* env, jclass clazz,
    498         jlong connectionPtr, jlong statementPtr) {
    499     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    500     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    501 
    502     int err = executeOneRowQuery(env, connection, statement);
    503     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
    504         return sqlite3_column_int64(statement, 0);
    505     }
    506     return -1;
    507 }
    508 
    509 static jstring nativeExecuteForString(JNIEnv* env, jclass clazz,
    510         jlong connectionPtr, jlong statementPtr) {
    511     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    512     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    513 
    514     int err = executeOneRowQuery(env, connection, statement);
    515     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
    516         const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(statement, 0));
    517         if (text) {
    518             size_t length = sqlite3_column_bytes16(statement, 0) / sizeof(jchar);
    519             return env->NewString(text, length);
    520         }
    521     }
    522     return NULL;
    523 }
    524 
    525 static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) {
    526     int error = 0;
    527     int fd = ashmem_create_region(NULL, length);
    528     if (fd < 0) {
    529         error = errno;
    530         ALOGE("ashmem_create_region failed: %s", strerror(error));
    531     } else {
    532         if (length > 0) {
    533             void* ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    534             if (ptr == MAP_FAILED) {
    535                 error = errno;
    536                 ALOGE("mmap failed: %s", strerror(error));
    537             } else {
    538                 memcpy(ptr, data, length);
    539                 munmap(ptr, length);
    540             }
    541         }
    542 
    543         if (!error) {
    544             if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
    545                 error = errno;
    546                 ALOGE("ashmem_set_prot_region failed: %s", strerror(errno));
    547             } else {
    548                 return fd;
    549             }
    550         }
    551 
    552         close(fd);
    553     }
    554 
    555     jniThrowIOException(env, error);
    556     return -1;
    557 }
    558 
    559 static jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz,
    560         jlong connectionPtr, jlong statementPtr) {
    561     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    562     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    563 
    564     int err = executeOneRowQuery(env, connection, statement);
    565     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
    566         const void* blob = sqlite3_column_blob(statement, 0);
    567         if (blob) {
    568             int length = sqlite3_column_bytes(statement, 0);
    569             if (length >= 0) {
    570                 return createAshmemRegionWithData(env, blob, length);
    571             }
    572         }
    573     }
    574     return -1;
    575 }
    576 
    577 enum CopyRowResult {
    578     CPR_OK,
    579     CPR_FULL,
    580     CPR_ERROR,
    581 };
    582 
    583 static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
    584         sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
    585     // Allocate a new field directory for the row.
    586     status_t status = window->allocRow();
    587     if (status) {
    588         LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
    589                 startPos, addedRows, status);
    590         return CPR_FULL;
    591     }
    592 
    593     // Pack the row into the window.
    594     CopyRowResult result = CPR_OK;
    595     for (int i = 0; i < numColumns; i++) {
    596         int type = sqlite3_column_type(statement, i);
    597         if (type == SQLITE_TEXT) {
    598             // TEXT data
    599             const char* text = reinterpret_cast<const char*>(
    600                     sqlite3_column_text(statement, i));
    601             // SQLite does not include the NULL terminator in size, but does
    602             // ensure all strings are NULL terminated, so increase size by
    603             // one to make sure we store the terminator.
    604             size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
    605             status = window->putString(addedRows, i, text, sizeIncludingNull);
    606             if (status) {
    607                 LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d",
    608                         sizeIncludingNull, startPos + addedRows, i, status);
    609                 result = CPR_FULL;
    610                 break;
    611             }
    612             LOG_WINDOW("%d,%d is TEXT with %u bytes",
    613                     startPos + addedRows, i, sizeIncludingNull);
    614         } else if (type == SQLITE_INTEGER) {
    615             // INTEGER data
    616             int64_t value = sqlite3_column_int64(statement, i);
    617             status = window->putLong(addedRows, i, value);
    618             if (status) {
    619                 LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
    620                         i, status);
    621                 result = CPR_FULL;
    622                 break;
    623             }
    624             LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
    625         } else if (type == SQLITE_FLOAT) {
    626             // FLOAT data
    627             double value = sqlite3_column_double(statement, i);
    628             status = window->putDouble(addedRows, i, value);
    629             if (status) {
    630                 LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
    631                         i, status);
    632                 result = CPR_FULL;
    633                 break;
    634             }
    635             LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
    636         } else if (type == SQLITE_BLOB) {
    637             // BLOB data
    638             const void* blob = sqlite3_column_blob(statement, i);
    639             size_t size = sqlite3_column_bytes(statement, i);
    640             status = window->putBlob(addedRows, i, blob, size);
    641             if (status) {
    642                 LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d",
    643                         size, startPos + addedRows, i, status);
    644                 result = CPR_FULL;
    645                 break;
    646             }
    647             LOG_WINDOW("%d,%d is Blob with %u bytes",
    648                     startPos + addedRows, i, size);
    649         } else if (type == SQLITE_NULL) {
    650             // NULL field
    651             status = window->putNull(addedRows, i);
    652             if (status) {
    653                 LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
    654                         i, status);
    655                 result = CPR_FULL;
    656                 break;
    657             }
    658 
    659             LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
    660         } else {
    661             // Unknown data
    662             ALOGE("Unknown column type when filling database window");
    663             throw_sqlite3_exception(env, "Unknown column type when filling window");
    664             result = CPR_ERROR;
    665             break;
    666         }
    667     }
    668 
    669     // Free the last row if if was not successfully copied.
    670     if (result != CPR_OK) {
    671         window->freeLastRow();
    672     }
    673     return result;
    674 }
    675 
    676 static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
    677         jlong connectionPtr, jlong statementPtr, jlong windowPtr,
    678         jint startPos, jint requiredPos, jboolean countAllRows) {
    679     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    680     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    681     CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    682 
    683     status_t status = window->clear();
    684     if (status) {
    685         String8 msg;
    686         msg.appendFormat("Failed to clear the cursor window, status=%d", status);
    687         throw_sqlite3_exception(env, connection->db, msg.string());
    688         return 0;
    689     }
    690 
    691     int numColumns = sqlite3_column_count(statement);
    692     status = window->setNumColumns(numColumns);
    693     if (status) {
    694         String8 msg;
    695         msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
    696                 numColumns, status);
    697         throw_sqlite3_exception(env, connection->db, msg.string());
    698         return 0;
    699     }
    700 
    701     int retryCount = 0;
    702     int totalRows = 0;
    703     int addedRows = 0;
    704     bool windowFull = false;
    705     bool gotException = false;
    706     while (!gotException && (!windowFull || countAllRows)) {
    707         int err = sqlite3_step(statement);
    708         if (err == SQLITE_ROW) {
    709             LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
    710             retryCount = 0;
    711             totalRows += 1;
    712 
    713             // Skip the row if the window is full or we haven't reached the start position yet.
    714             if (startPos >= totalRows || windowFull) {
    715                 continue;
    716             }
    717 
    718             CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
    719             if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) {
    720                 // We filled the window before we got to the one row that we really wanted.
    721                 // Clear the window and start filling it again from here.
    722                 // TODO: Would be nicer if we could progressively replace earlier rows.
    723                 window->clear();
    724                 window->setNumColumns(numColumns);
    725                 startPos += addedRows;
    726                 addedRows = 0;
    727                 cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
    728             }
    729 
    730             if (cpr == CPR_OK) {
    731                 addedRows += 1;
    732             } else if (cpr == CPR_FULL) {
    733                 windowFull = true;
    734             } else {
    735                 gotException = true;
    736             }
    737         } else if (err == SQLITE_DONE) {
    738             // All rows processed, bail
    739             LOG_WINDOW("Processed all rows");
    740             break;
    741         } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
    742             // The table is locked, retry
    743             LOG_WINDOW("Database locked, retrying");
    744             if (retryCount > 50) {
    745                 ALOGE("Bailing on database busy retry");
    746                 throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
    747                 gotException = true;
    748             } else {
    749                 // Sleep to give the thread holding the lock a chance to finish
    750                 usleep(1000);
    751                 retryCount++;
    752             }
    753         } else {
    754             throw_sqlite3_exception(env, connection->db);
    755             gotException = true;
    756         }
    757     }
    758 
    759     LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
    760             "to the window in %d bytes",
    761             statement, totalRows, addedRows, window->size() - window->freeSpace());
    762     sqlite3_reset(statement);
    763 
    764     // Report the total number of rows on request.
    765     if (startPos > totalRows) {
    766         ALOGE("startPos %d > actual rows %d", startPos, totalRows);
    767     }
    768     if (totalRows > 0 && addedRows == 0) {
    769         String8 msg;
    770         msg.appendFormat("Row too big to fit into CursorWindow requiredPos=%d, totalRows=%d",
    771                 requiredPos, totalRows);
    772         throw_sqlite3_exception(env, SQLITE_TOOBIG, NULL, msg.string());
    773         return 0;
    774     }
    775 
    776     jlong result = jlong(startPos) << 32 | jlong(totalRows);
    777     return result;
    778 }
    779 
    780 static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jlong connectionPtr) {
    781     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    782 
    783     int cur = -1;
    784     int unused;
    785     sqlite3_db_status(connection->db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &unused, 0);
    786     return cur;
    787 }
    788 
    789 static void nativeCancel(JNIEnv* env, jobject clazz, jlong connectionPtr) {
    790     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    791     connection->canceled = true;
    792 }
    793 
    794 static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
    795         jboolean cancelable) {
    796     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    797     connection->canceled = false;
    798 
    799     if (cancelable) {
    800         sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
    801                 connection);
    802     } else {
    803         sqlite3_progress_handler(connection->db, 0, NULL, NULL);
    804     }
    805 }
    806 
    807 
    808 static const JNINativeMethod sMethods[] =
    809 {
    810     /* name, signature, funcPtr */
    811     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
    812             (void*)nativeOpen },
    813     { "nativeClose", "(J)V",
    814             (void*)nativeClose },
    815     { "nativeRegisterCustomFunction", "(JLandroid/database/sqlite/SQLiteCustomFunction;)V",
    816             (void*)nativeRegisterCustomFunction },
    817     { "nativeRegisterLocalizedCollators", "(JLjava/lang/String;)V",
    818             (void*)nativeRegisterLocalizedCollators },
    819     { "nativePrepareStatement", "(JLjava/lang/String;)J",
    820             (void*)nativePrepareStatement },
    821     { "nativeFinalizeStatement", "(JJ)V",
    822             (void*)nativeFinalizeStatement },
    823     { "nativeGetParameterCount", "(JJ)I",
    824             (void*)nativeGetParameterCount },
    825     { "nativeIsReadOnly", "(JJ)Z",
    826             (void*)nativeIsReadOnly },
    827     { "nativeGetColumnCount", "(JJ)I",
    828             (void*)nativeGetColumnCount },
    829     { "nativeGetColumnName", "(JJI)Ljava/lang/String;",
    830             (void*)nativeGetColumnName },
    831     { "nativeBindNull", "(JJI)V",
    832             (void*)nativeBindNull },
    833     { "nativeBindLong", "(JJIJ)V",
    834             (void*)nativeBindLong },
    835     { "nativeBindDouble", "(JJID)V",
    836             (void*)nativeBindDouble },
    837     { "nativeBindString", "(JJILjava/lang/String;)V",
    838             (void*)nativeBindString },
    839     { "nativeBindBlob", "(JJI[B)V",
    840             (void*)nativeBindBlob },
    841     { "nativeResetStatementAndClearBindings", "(JJ)V",
    842             (void*)nativeResetStatementAndClearBindings },
    843     { "nativeExecute", "(JJ)V",
    844             (void*)nativeExecute },
    845     { "nativeExecuteForLong", "(JJ)J",
    846             (void*)nativeExecuteForLong },
    847     { "nativeExecuteForString", "(JJ)Ljava/lang/String;",
    848             (void*)nativeExecuteForString },
    849     { "nativeExecuteForBlobFileDescriptor", "(JJ)I",
    850             (void*)nativeExecuteForBlobFileDescriptor },
    851     { "nativeExecuteForChangedRowCount", "(JJ)I",
    852             (void*)nativeExecuteForChangedRowCount },
    853     { "nativeExecuteForLastInsertedRowId", "(JJ)J",
    854             (void*)nativeExecuteForLastInsertedRowId },
    855     { "nativeExecuteForCursorWindow", "(JJJIIZ)J",
    856             (void*)nativeExecuteForCursorWindow },
    857     { "nativeGetDbLookaside", "(J)I",
    858             (void*)nativeGetDbLookaside },
    859     { "nativeCancel", "(J)V",
    860             (void*)nativeCancel },
    861     { "nativeResetCancel", "(JZ)V",
    862             (void*)nativeResetCancel },
    863 };
    864 
    865 int register_android_database_SQLiteConnection(JNIEnv *env)
    866 {
    867     jclass clazz = FindClassOrDie(env, "android/database/sqlite/SQLiteCustomFunction");
    868 
    869     gSQLiteCustomFunctionClassInfo.name = GetFieldIDOrDie(env, clazz, "name", "Ljava/lang/String;");
    870     gSQLiteCustomFunctionClassInfo.numArgs = GetFieldIDOrDie(env, clazz, "numArgs", "I");
    871     gSQLiteCustomFunctionClassInfo.dispatchCallback = GetMethodIDOrDie(env, clazz,
    872             "dispatchCallback", "([Ljava/lang/String;)V");
    873 
    874     clazz = FindClassOrDie(env, "java/lang/String");
    875     gStringClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
    876 
    877     return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteConnection", sMethods,
    878                                 NELEM(sMethods));
    879 }
    880 
    881 } // namespace android
    882