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