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