Question

I m getting unsatisfied link error in native method

Logcat main exception

UnsatisfiedLinkError: Native method not found: rg.sqlite.database.sqlite.SQLiteConnection.nativeHasCodec:()Z

Complete Logcat

02-04 16:29:12.807: E/AndroidRuntime(5087): FATAL EXCEPTION: main
02-04 16:29:12.807: E/AndroidRuntime(5087): java.lang.UnsatisfiedLinkError: Native method not found: org.sqlite.database.sqlite.SQLiteConnection.nativeHasCodec:()Z
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnection.nativeHasCodec(Native Method)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnection.hasCodec(SQLiteConnection.java:160)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.hasCodec(SQLiteDatabase.java:2195)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnectionPool.setMaxConnectionPoolSizeLocked(SQLiteConnectionPool.java:952)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnectionPool.<init>(SQLiteConnectionPool.java:153)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:179)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.example.samplesqlitedb.SearchDataDB.getAutoSuggestion(SearchDataDB.java:33)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.example.samplesqlitedb.MainActivity$2.onClick(MainActivity.java:56)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.view.View.performClick(View.java:4084)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.view.View$PerformClick.run(View.java:16966)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.os.Handler.handleCallback(Handler.java:615)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.os.Handler.dispatchMessage(Handler.java:92)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.os.Looper.loop(Looper.java:137)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.app.ActivityThread.main(ActivityThread.java:4745)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at java.lang.reflect.Method.invokeNative(Native Method)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at java.lang.reflect.Method.invoke(Method.java:511)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at dalvik.system.NativeStart.main(Native Method)

Custom Java file SQLiteConnection https://www.dropbox.com/s/5ex6u9rzkwb7kqq/SQLiteConnection.java error on line no. 160

Here is the source cpp files from where i have compiled and created the binary "libsqliteX.so" file http://www.sqlite.org/android/tree?ci=trunk&re=jni|src/org/sqlite/data&expand

my .so file https://www.dropbox.com/s/d0u5pyhke54tcd6/libsqliteX.so

so i think i have to modify in the native method to resolve this problem

static jboolean nativeHasCodec(JNIEnv* env, jobject clazz){
#ifdef SQLITE_HAS_CODEC
return true;
#else
return false;
#endif
}

Here is CDT GLOBAL BUILD CONSOLE

**** Build of configuration Default for project CustomSqlite ****

D:\software\adt-bundle-windows-x86-20130522\adt-bundle-windows-x86-20130522\android-ndk-r9-windows-x86\android-ndk-r9\ndk-build.cmd all 
"Compile++ thumb : sqliteX <= android_database_SQLiteCommon.cpp
"Compile++ thumb : sqliteX <= android_database_SQLiteConnection.cpp
"Compile++ thumb : sqliteX <= android_database_SQLiteGlobal.cpp
"Compile++ thumb : sqliteX <= android_database_SQLiteDebug.cpp
"Compile++ thumb : sqliteX <= JNIHelp.cpp
"Compile++ thumb : sqliteX <= JniConstants.cpp
"Compile thumb : sqliteX <= sqlite3.c
SharedLibrary  : libsqliteX.so
Install        : libsqliteX.so => libs/armeabi/libsqliteX.so

**** Build Finished ****

**** Build of configuration Default for project CustomSqlite ****

D:\software\adt-bundle-windows-x86-20130522\adt-bundle-windows-x86-20130522\android-ndk-r9-windows-x86\android-ndk-r9\ndk-build.cmd all 
Install        : libsqliteX.so => libs/armeabi/libsqliteX.so

**** Build Finished ****

so i think .so was generated properly

Here is my Customsqlite.java

it is having methods

package org.sqlite.app.customsqlite;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import org.sqlite.database.DatabaseErrorHandler;
import org.sqlite.database.sqlite.SQLiteDatabase;
import org.sqlite.database.sqlite.SQLiteOpenHelper;
import org.sqlite.database.sqlite.SQLiteStatement;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

class DoNotDeleteErrorHandler implements DatabaseErrorHandler {
private static final String TAG = "DoNotDeleteErrorHandler";
public void onCorruption(SQLiteDatabase dbObj) {
    Log.e(TAG,"Corruption reported by sqlite on database: " + dbObj.getPath());
}
}

public class CustomSqlite extends Activity {
private TextView myTV;  
EditText query;
File DB_PATH;
String searchedword;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    myTV = (TextView) findViewById(R.id.tv_widget);
    query = (EditText) findViewById(R.id.query);
}

public void report_version() {
    SQLiteDatabase db = null;
    SQLiteStatement st;
    String res;

    db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
    st = db.compileStatement("SELECT sqlite_version()");
    res = st.simpleQueryForString();

    myTV.append("SQLite version " + res + "\n\n");
}

public void test_warning(String name, String warning) {
    myTV.append("WARNING:" + name + ": " + warning + "\n");
}

public void test_result(String name, String res, String expected) {
    myTV.append(name + "... ");


    if (res.equals(expected)) {
        myTV.append("ok\n");
    } else {

        myTV.append("FAILED\n");
        myTV.append("   res=     \"" + res + "\"\n");
        myTV.append("   expected=\"" + expected + "\"\n");
    }
}

/*
 * * Test if the database at DB_PATH is encrypted or not. The db* is assumed
 * to be encrypted if the first 6 bytes are anything* other than "SQLite".**
 * If the test reveals that the db is encrypted, return the string*
 * "encrypted". Otherwise, "unencrypted".
 */
public String db_is_encrypted() throws Exception {
    FileInputStream in = new FileInputStream(DB_PATH);
    byte[] buffer = new byte[6];
    in.read(buffer, 0, 6);
    String res = "encrypted";
    if (Arrays.equals(buffer, (new String("SQLite")).getBytes())) {
        res = "unencrypted";
    }
    in.close();
    return res;
}

/*
 * * Use a Cursor to loop through the results of a SELECT query.
 */
public void syno() throws Exception {
    DB_PATH = new File("/storage/sdcard1/sk2.db");
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    Cursor c = db.rawQuery("SELECT synsetid, w2.lemma FROM sense LEFT JOIN word AS w2 ON w2.wordid=sense.wordid WHERE sense.synsetid IN (SELECT sense.synsetid FROM word AS w1 LEFT JOIN sense ON w1.wordid=sense.wordid WHERE w1.lemma='"+ searchedword+ "') AND w2.lemma<>'"+ searchedword + "'", null);
    ArrayList<String> list1 = new ArrayList<String>();
    if (c != null) {

        if (c.getCount() > 0) {
            c.moveToFirst();
            do {
                list1.add(c.getString(1));
            } while (c.moveToNext());

            }
        myTV.append("\n\nSYNONYM " + list1.toString());
    }



    db.close();

}

/*
 * * If this is a SEE build, check that encrypted databases work.
 */
public void anto() throws Exception {

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    Cursor c = db.rawQuery("SELECT DISTINCT(w2.lemma) as lemma from word w1 left join sense se1 on w1.wordid = se1.wordid left join synset sy1 on se1.synsetid = sy1.synsetid left join lexlinkref on sy1.synsetid = lexlinkref.synset1id and w1.wordid = lexlinkref.word1id left join word w2 on lexlinkref.word2id = w2.wordid where w1.lemma = '"+ searchedword + "' and lexlinkref.linkid=30",null);
    ArrayList<String> list1 = new ArrayList<String>();
    if (c.getCount() > 0) {
        c.moveToFirst();
        do {            
        list1.add(c.getString(0));
        } while (c.moveToNext());

    }
    myTV.append("\n\nANTONYMS "+list1.toString());
    db.close();


}

class MyHelper extends SQLiteOpenHelper {
    public MyHelper(Context ctx) {
        super(ctx, DB_PATH.getPath(), null, 1);
    }

    public void onConfigure(SQLiteDatabase db) {
        db.execSQL("PRAGMA key = 'secret'");
    }

    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE t1(x)");
    }

    public void onUpgrade(SQLiteDatabase db, int iOld, int iNew) {
    }
}

/*
 * * If this is a SEE build, check that SQLiteOpenHelper still works.
 */
public void def() throws Exception {
    DB_PATH = new File("/storage/sdcard1/sk2.db");
    String DEFINITION = "select pos, definition, sample FROM word INNER JOIN sense ON word.wordid = sense.wordid INNER JOIN synset ON sense.synsetid = synset.synsetid LEFT JOIN sample ON sample.synsetid =  synset.synsetid  WHERE lemma ='"+ searchedword + "'";
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    ArrayList<String> list1 = new ArrayList<String>();
    Cursor mcursor = db.rawQuery(DEFINITION, null);
    mcursor.moveToFirst();
    if (mcursor.getCount() > 0) {
        do {

            list1.add(mcursor.getString(1));
        } while (mcursor.moveToNext());

    }
    myTV.append("\nDEFINATION " + list1.toString());
    db.close();
}

public void run_the_tests(View view) {
    System.loadLibrary("sqliteX");
    myTV.setText("");       
    searchedword = query.getText().toString();
    try {
        report_version();
        def();
        syno();
        anto();

    } catch (Exception e) {
        myTV.append("Exception: " + e.toString() + "\n");
        myTV.append(android.util.Log.getStackTraceString(e) + "\n");
    }
}
}

Thanks

Was it helpful?

Solution

I have resolved this issue my self by adding

System.loadLibrary("sqliteX");

To each method where they are created

LIKE THIS:

public HashMap<String, ArrayList<String>> word_quiz(String qry) {
    System.loadLibrary("sqliteX");
    ArrayList<String> list1 = new ArrayList<String>();
    ArrayList<String> list2 = new ArrayList<String>();
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH+ "/sk1.db", null);
    Cursor mcursor = db.rawQuery(qry, null);
    try {
        mcursor.moveToFirst();
        do {
            list1.add(mcursor.getString(0));
            list2.add(mcursor.getString(1));
        } while (mcursor.moveToNext());

    } catch (IndexOutOfBoundsException e) {
        if (MainActivity.logcat_status) {
            Log.e("Error", e + "");
        }
    }
    mcursor.close();
    mcursor = null;
    HashMap<String, ArrayList<String>> final_list = new HashMap<String, ArrayList<String>>();
    final_list.put("list1", list1);
    final_list.put("list2", list2);
    db.close();
    return final_list;

}

Now its working fine

I think I can also use a constructor to load the library "sqliteX"

Thanks guys for considering my question :)

OTHER TIPS

The exception originates from your code at com.example.samplesqlitedb.MainActivity$2.onClick() at com/example/samplesqlitedb/MainActivity.java:56, but System.loadLibrary() is called from org.sqlite.app.customsqlite.CustomSqlite.run_the_tests(). There is no evidence that the org.sqlite.app.customsqlite.CustomSqlite activity was even loaded into JVM when this happened.

I would suggest to load libsqliteX.so from the static constructor of org.sqlite.database.sqlite.SQLiteConnection class. Maybe you can find some better place - e.g. com.example.samplesqlitedb.SearchDataDB class, or the class in your app that extends android.app.Application (if you have such).

As opposed to the accepted answer consider inserting the call to the System.loadLibrary function only once, e.g. into the DbHelper.

public class MyDbHelper extends SQLiteOpenHelper {

   static {
      System.loadLibrary("sqliteX");
   }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top