2013年6月27日 星期四

移植 android 4.2.2_r1.2 到 am335xevm_sk board 上....

目前 TI Release 的是4.1.2 , 發現這個版本不符合我們想要的 , 消費性產品 有時候使用者在追求新的東西 , 今天您買一台 NB , 隨機附上 Windows 7 感覺如何 ?? "掉漆"

所以我們的Android Base 產品只能跟著使用者的喜好 , 附上最新的版本.
好吧 , 開始一步一步移植吧 !! 順便將重點寫下來, 將來要更新新版Android 才有頭緒.

不多說, 一步一步開始吧 !! (目前還在實作中, 下列步驟可能有錯 )
 (藍色是內容 , 紅色是註記和說明)

1. Create device director on ./device/JeffLab/testdev
    ====> mkdir ./device/xxxx/yyyy , xxxx = vendor name , yyyy = device name .

2. Create AndroidProduct.mk file in ./device/JeffLab/testdev

    PRODUCT_MAKEFILES := \
        $(LOCAL_DIR)/JeffLab_testdev.mk
  ====> xxxxxxx.mk need same TARGET_PRODUCT=xxxxxxx



3. Create JeffLab_testdev.mk make file in ./device/JeffLab/testdev/

    ## ========
    $(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk)
    $(call inherit-product, $(LOCAL_PATH)/device.mk)

    ## ======== Setting product information.
    PRODUCT_NAME := JeffLab_testdev      ===> must same as TARGET_PRODUCT=xxxxxxx
    PRODUCT_DEVICE := testdev            ===> must same as ./device/JeffLab/xxxx/....
    PRODUCT_BRAND := Android
    PRODUCT_MODEL := JeffLab testdev

4. Create BoardConfig.mk file in ./device/JeffLab/testdev/

    ## ======== Setting Arch type
    TARGET_CPU_ABI := armeabi-v7a
    TARGET_CPU_ABI2 := armeabi
    TARGET_ARCH := arm
    TARGET_ARCH_VARIANT := armv7-a-neon
    ARCH_ARM_HAVE_TLS_REGISTER := true

    ## ======== setting kernel
    TARGET_NO_KERNEL := true

    ## ======== bluetooth setting.
    BOARD_HAVE_BLUETOOTH := false
    BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := $(LOCAL_PATH)/bluetooth


5. Create device.mk file in ./device/JeffLab/testdev/

    ## ========
    PRODUCT_COPY_FILES    :=

    ## ========
    PRODUCT_PACKAGES     :=

    ## ========
    ## include Our APP direct
    $(call inherit-product-if-exists, $(PRJ_INST_APP_NAME))
    $(call inherit-product, frameworks/native/build/tablet-dalvik-heap.mk)


6. Create director ./device/JeffLab/testdev/bluetooth
7. Create bdroid_buildcfg.h file in ./device/JeffLab/testdev/bluetooth/


    #ifndef _BDROID_BUILDCFG_H
    #define _BDROID_BUILDCFG_H

    #define BTM_DEF_LOCAL_NAME   "JeffLab testdev"    ====> Bluetooth device name .

    #endif



2013年6月17日 星期一

sqlite 加密 API (Java)

之前測試了Sqlite 加密的 .so file & command line testing utility 後, 現在要來修改 Java 端的 API 了 , 讓我們的 APP 可以使用 !!
加密就是為了不讓其他APP可以任意使用,所以也不會和標準相容啦 !!

開始一步步來修改吧 !

A.大部份database 操作都由 SQLiteOpenHelper class 開始.
   一般都由 SQLiteDatabase.getReadableDatabase() 來開始 Database file.
   我們就增加一個 SQLiteDatabase.getReadableEncryDB(String key) ,
   可以帶密碼的 function 開始, Java 支援多型態 ,所以修正
   getDatabaseLocked(boolean writable) 為
   getDatabaseLocked(boolean writable,String key) ,並且保留原來的,整個
   SQLiteOpenHelper.java 的 diff 如下:


diff -Nura TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java    2012-12-17 15:18:27.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java    2013-06-14 13:24:10.974298336 +0800
@@ -183,13 +183,29 @@
      * @return a database object valid until {@link #getWritableDatabase}
      *     or {@link #close} is called.
      */
-    public SQLiteDatabase getReadableDatabase() {
-        synchronized (this) {
+    public SQLiteDatabase getReadableDatabase()
+    {
+        synchronized (this)
+        {
             return getDatabaseLocked(false);
         }
     }

-    private SQLiteDatabase getDatabaseLocked(boolean writable) {
+    public SQLiteDatabase getReadableEncryDB(String key)
+    {
+        synchronized (this)
+        {
+            return getDatabaseLocked(false,key);
+        }
+    }
+
+    private SQLiteDatabase getDatabaseLocked(boolean writable)
+    {
+        return getDatabaseLocked(writable,null);
+    }
+
+    private SQLiteDatabase getDatabaseLocked(boolean writable,String key)
+    {
         if (mDatabase != null) {
             if (!mDatabase.isOpen()) {
                 // Darn!  The user closed the database by calling mDatabase.close().
@@ -205,7 +221,8 @@
         }

         SQLiteDatabase db = mDatabase;
-        try {
+        try
+        {
             mIsInitializing = true;

             if (db != null) {
@@ -215,54 +232,78 @@
             } else if (mName == null) {
                 db = SQLiteDatabase.create(null);
             } else {
-                try {
-                    if (DEBUG_STRICT_READONLY && !writable) {
+                try
+                {
+                    if (DEBUG_STRICT_READONLY && !writable)
+                    {
                         final String path = mContext.getDatabasePath(mName).getPath();
-                        db = SQLiteDatabase.openDatabase(path, mFactory,
+                        if ( key != null )
+                            db = SQLiteDatabase.openDatabase(path, mFactory,
                                 SQLiteDatabase.OPEN_READONLY, mErrorHandler);
-                    } else {
-                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
-                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
-                                mFactory, mErrorHandler);
+                        else
+                            db = SQLiteDatabase.openDatabase(path, mFactory,
+                                SQLiteDatabase.OPEN_READONLY, key, mErrorHandler);
+                    }
+                    else
+                    {
+                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
+                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
+                                mFactory,key, mErrorHandler);
                     }
-                } catch (SQLiteException ex) {
-                    if (writable) {
+                }
+                catch (SQLiteException ex)
+                {
+                    if (writable)
+                    {
                         throw ex;
                     }
+
                     Log.e(TAG, "Couldn't open " + mName
                             + " for writing (will try read-only):", ex);
                     final String path = mContext.getDatabasePath(mName).getPath();
-                    db = SQLiteDatabase.openDatabase(path, mFactory,
-                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);
+                    db = SQLiteDatabase.openDatabase(path, mFactory,
+                                SQLiteDatabase.OPEN_READONLY,key, mErrorHandler);
                 }
             }

             onConfigure(db);

-            final int version = db.getVersion();
-            if (version != mNewVersion) {
-                if (db.isReadOnly()) {
-                    throw new SQLiteException("Can't upgrade read-only database from version " +
-                            db.getVersion() + " to " + mNewVersion + ": " + mName);
-                }
-
-                db.beginTransaction();
-                try {
-                    if (version == 0) {
-                        onCreate(db);
-                    } else {
-                        if (version > mNewVersion) {
-                            onDowngrade(db, version, mNewVersion);
-                        } else {
-                            onUpgrade(db, version, mNewVersion);
-                        }
-                    }
-                    db.setVersion(mNewVersion);
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
-                }
-            }
+            final int version = db.getVersion();
+            if (version != mNewVersion)
+            {
+                if (db.isReadOnly())
+                {
+                    throw new SQLiteException("Can't upgrade read-only database from version " +
+                        db.getVersion() + " to " + mNewVersion + ": " + mName);
+                }
+
+                db.beginTransaction();
+                try
+                {
+                    if (version == 0)
+                    {
+                        onCreate(db);
+                    }
+                    else
+                    {
+                        if (version > mNewVersion)
+                        {
+                            onDowngrade(db, version, mNewVersion);
+                        }
+                        else
+                        {
+                            onUpgrade(db, version, mNewVersion);
+                        }
+                    }
+
+                    db.setVersion(mNewVersion);
+                    db.setTransactionSuccessful();
+                }
+                finally
+                {
+                    db.endTransaction();
+                }
+            }

             onOpen(db);

@@ -272,7 +313,9 @@

             mDatabase = db;
             return db;
-        } finally {
+        }
+        finally
+        {
             mIsInitializing = false;
             if (db != null && db != mDatabase) {
                 db.close();
@@ -283,10 +326,13 @@
     /**
      * Close any open database object.
      */
-    public synchronized void close() {
+    public synchronized void close()
+    {
+
         if (mIsInitializing) throw new IllegalStateException("Closed during initialization");

-        if (mDatabase != null && mDatabase.isOpen()) {
+        if (mDatabase != null && mDatabase.isOpen())
+        {
             mDatabase.close();
             mDatabase = null;
         }


B.接著會啟動SQLiteDatebase.java 中的 openDatabase() ,相同的,也將 password(key)
    帶入, 整個 java 的 diff 如下:



diff -Nura TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java    2012-12-17 15:18:27.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java    2013-06-14 13:22:52.593677892 +0800
@@ -251,11 +251,13 @@
      */
     public static final int MAX_SQL_CACHE_SIZE = 100;

-    private SQLiteDatabase(String path, int openFlags, CursorFactory cursorFactory,
-            DatabaseErrorHandler errorHandler) {
+
+    private SQLiteDatabase(String path, int openFlags, CursorFactory cursorFactory, String key,
+            DatabaseErrorHandler errorHandler)
+    {
         mCursorFactory = cursorFactory;
         mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
-        mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
+        mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags,key);
     }

     @Override
@@ -689,11 +691,18 @@
      * @throws SQLiteException if the database cannot be opened
      */
     public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
-            DatabaseErrorHandler errorHandler) {
-        SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
+            DatabaseErrorHandler errorHandler)
+    {
+        return openDatabase(path, factory, flags, null,errorHandler);
+    }
+
+    public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,String key ,
+            DatabaseErrorHandler errorHandler)
+    {
+        SQLiteDatabase db = new SQLiteDatabase(path, flags, factory,key, errorHandler);
         db.open();
         return db;
-    }
+    }

     /**
      * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
@@ -783,29 +792,39 @@
         }
     }

-    private void open() {
-        try {
-            try {
+    private void open()
+    {
+        try
+        {
+            try
+            {
                 openInner();
-            } catch (SQLiteDatabaseCorruptException ex) {
+            }
+            catch (SQLiteDatabaseCorruptException ex)
+            {
                 onCorruption();
                 openInner();
             }
-        } catch (SQLiteException ex) {
+        }
+        catch (SQLiteException ex)
+        {
             Log.e(TAG, "Failed to open database '" + getLabel() + "'.", ex);
             close();
             throw ex;
         }
     }

-    private void openInner() {
-        synchronized (mLock) {
+    private void openInner()
+    {
+        synchronized (mLock)
+        {
             assert mConnectionPoolLocked == null;
             mConnectionPoolLocked = SQLiteConnectionPool.open(mConfigurationLocked);
             mCloseGuardLocked.open("close");
         }

-        synchronized (sActiveDatabases) {
+        synchronized (sActiveDatabases)
+        {
             sActiveDatabases.put(this, null);
         }
     }
@@ -1713,7 +1732,7 @@
      * Returns true if the new version code is greater than the current database version.
      *
      * @param newVersion The new version code.
-     * @return True if the new version code is greater than the current database version.
+     * @return True if the new version code is greater than the current database version.
      */
     public boolean needUpgrade(int newVersion) {
         return newVersion > getVersion();


C. openDatabase 會 new SQLiteDatabaseConfigureation , 接著我們在這裡多
    一個變數 key , 來存放 password.
   diff 如下:


diff -Nura TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java    2012-12-17 15:18:27.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java    2013-06-07 15:45:13.818910296 +0800
@@ -45,6 +45,8 @@
      */
     public static final String MEMORY_DB_PATH = ":memory:";

+    public final String key;
+
     /**
      * The database path.
      */
@@ -96,11 +98,31 @@
      * @param path The database path.
      * @param openFlags Open flags for the database, such as {@link SQLiteDatabase#OPEN_READWRITE}.
      */
-    public SQLiteDatabaseConfiguration(String path, int openFlags) {
+    public SQLiteDatabaseConfiguration(String path, int openFlags)
+    {
+         if (path == null) {
+            throw new IllegalArgumentException("path must not be null.");
+        }
+
+        this.key = null;
+
+        this.path = path;
+        label = stripPathForLogs(path);
+        this.openFlags = openFlags;
+
+        // Set default values for optional parameters.
+        maxSqlCacheSize = 25;
+        locale = Locale.getDefault();
+    }
+
+    public SQLiteDatabaseConfiguration(String path, int openFlags,String key)
+    {
         if (path == null) {
             throw new IllegalArgumentException("path must not be null.");
         }

+        this.key = key;
+
         this.path = path;
         label = stripPathForLogs(path);
         this.openFlags = openFlags;
@@ -120,6 +142,7 @@
             throw new IllegalArgumentException("other must not be null.");
         }

+        this.key = other.key;
         this.path = other.path;
         this.label = other.label;
         updateParametersFrom(other);



D.整個 database open 過程最後回來到 SQLiteConnection.java 中 , 並且呼叫
   nativeOpen() , 這個是 JNI Function.
   我們在 open function 內將剛存在 Configure 內的 Password 一起帶給 nativeOpen().
   在這個 class 中,我們多設定了一個 rekey() function , 這是預留,目前並不打算有rekey
   的功能 , diff file 如下:

diff -Nura TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteConnection.java TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteConnection.java
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/java/android/database/sqlite/SQLiteConnection.java    2012-12-17 15:18:27.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/java/android/database/sqlite/SQLiteConnection.java    2013-06-14 13:21:50.396218106 +0800
@@ -117,8 +117,9 @@
     // we can ensure that we detach the signal at the right time.
     private int mCancellationSignalAttachCount;

-    private static native int nativeOpen(String path, int openFlags, String label,
+    private static native int nativeOpen(String path, int openFlags, String label,String key,
             boolean enableTrace, boolean enableProfile);
+
     private static native void nativeClose(int connectionPtr);
     private static native void nativeRegisterCustomFunction(int connectionPtr,
             SQLiteCustomFunction function);
@@ -157,9 +158,13 @@
     private static native void nativeCancel(int connectionPtr);
     private static native void nativeResetCancel(int connectionPtr, boolean cancelable);

+    private static native int nativeReKey(int connectionPtr,String key);
+
+
     private SQLiteConnection(SQLiteConnectionPool pool,
             SQLiteDatabaseConfiguration configuration,
-            int connectionId, boolean primaryConnection) {
+            int connectionId, boolean primaryConnection)
+    {
         mPool = pool;
         mConfiguration = new SQLiteDatabaseConfiguration(configuration);
         mConnectionId = connectionId;
@@ -186,13 +191,17 @@
     // Called by SQLiteConnectionPool only.
     static SQLiteConnection open(SQLiteConnectionPool pool,
             SQLiteDatabaseConfiguration configuration,
-            int connectionId, boolean primaryConnection) {
+            int connectionId, boolean primaryConnection)
+    {
         SQLiteConnection connection = new SQLiteConnection(pool, configuration,
                 connectionId, primaryConnection);
-        try {
+        try
+        {
             connection.open();
             return connection;
-        } catch (SQLiteException ex) {
+        }
+        catch (SQLiteException ex)
+        {
             connection.dispose(false);
             throw ex;
         }
@@ -205,12 +214,13 @@
         dispose(false);
     }

-    private void open() {
+    private void open()
+    {
         mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
-                mConfiguration.label,
+                mConfiguration.label,mConfiguration.key,
                 SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);

-        setPageSize();
+        setPageSize();
         setForeignKeyModeFromConfiguration();
         setWalModeFromConfiguration();
         setJournalSizeLimit();
@@ -218,6 +228,13 @@
         setLocaleFromConfiguration();
     }

+    public void db_rekey(String key)
+    {
+        Log.e(TAG, "db_rekey() , Not finish ...... ");
+    }
+
+
+
     private void dispose(boolean finalized) {
         if (mCloseGuard != null) {
             if (finalized) {
@@ -239,10 +256,12 @@
     }

     private void setPageSize() {
-        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
+        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection)
+        {
             final long newValue = SQLiteGlobal.getDefaultPageSize();
             long value = executeForLong("PRAGMA page_size", null, null);
-            if (value != newValue) {
+            if (value != newValue)
+            {
                 execute("PRAGMA page_size=" + newValue, null, null);
             }
         }
@@ -268,11 +287,14 @@
         }
     }

-    private void setForeignKeyModeFromConfiguration() {
-        if (!mIsReadOnlyConnection) {
+    private void setForeignKeyModeFromConfiguration()
+    {
+        if (!mIsReadOnlyConnection)
+        {
             final long newValue = mConfiguration.foreignKeyConstraintsEnabled ? 1 : 0;
             long value = executeForLong("PRAGMA foreign_keys", null, null);
-            if (value != newValue) {
+            if (value != newValue)
+            {
                 execute("PRAGMA foreign_keys=" + newValue, null, null);
             }
         }
@@ -901,17 +923,23 @@
         return statement;
     }

-    private void releasePreparedStatement(PreparedStatement statement) {
+    private void releasePreparedStatement(PreparedStatement statement)
+    {
         statement.mInUse = false;
-        if (statement.mInCache) {
-            try {
+        if (statement.mInCache)
+        {
+            try
+            {
                 nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr);
-            } catch (SQLiteException ex) {
+            }
+            catch (SQLiteException ex)
+            {
                 // The statement could not be reset due to an error.  Remove it from the cache.
                 // When remove() is called, the cache will invoke its entryRemoved() callback,
                 // which will in turn call finalizePreparedStatement() to finalize and
                 // recycle the statement.
-                if (DEBUG) {
+                if (DEBUG)
+                {
                     Log.d(TAG, "Could not reset prepared statement due to an exception.  "
                             + "Removing it from the cache.  SQL: "
                             + trimSqlForDisplay(statement.mSql), ex);
@@ -919,7 +947,9 @@

                 mPreparedStatementCache.remove(statement.mSql);
             }
-        } else {
+        }
+        else
+        {
             finalizePreparedStatement(statement);
         }
     }
@@ -1240,7 +1270,8 @@
     }

     private final class PreparedStatementCache
-            extends LruCache<String, PreparedStatement> {
+            extends LruCache<String, PreparedStatement>
+    {
         public PreparedStatementCache(int size) {
             super(size);
         }


E.進入JNI CPP 階段 , 一樣宣告一個 rekey function 預留, 因為設定key 需要在
    sqlite3_open_v2 後馬上執行sqlite3_key 不然執行任何動作都會導致 超操作失敗.
    所以在 nativeOpen 中馬上檢查 key 是否 NULL , 如果不是就執行 sqlite3_key.
    當然要修改 Android.mk file 增加SQLITE_HAS_CODEC , 這樣才有 sqlite3_key
    Function.
    Androdi.mk & SQLiteConnection.cpp 的 diff 如下:

diff -Nura TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/jni/android_database_SQLiteConnection.cpp TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/jni/android_database_SQLiteConnection.cpp
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/jni/android_database_SQLiteConnection.cpp    2012-12-17 15:18:28.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/jni/android_database_SQLiteConnection.cpp    2013-06-14 13:30:11.300238584 +0800
@@ -109,13 +109,20 @@


 static jint nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
-        jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
-    int sqliteFlags;
-    if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
+        jstring labelStr,jstring keyStr, jboolean enableTrace, jboolean enableProfile)
+{
+int sqliteFlags;
+
+    if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY)
+    {
         sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
-    } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
+    }
+    else if (openFlags & SQLiteConnection::OPEN_READONLY)
+    {
         sqliteFlags = SQLITE_OPEN_READONLY;
-    } else {
+    }
+    else
+    {
         sqliteFlags = SQLITE_OPEN_READWRITE;
     }

@@ -129,13 +136,39 @@

     sqlite3* db;
     int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
-    if (err != SQLITE_OK) {
+    if (err != SQLITE_OK)
+    {
         throw_sqlite3_exception_errcode(env, err, "Could not open database");
         return 0;
     }

+#ifdef SQLITE_HAS_CODEC
+
+    if ( keyStr != NULL)
+    {
+        const char* keyChars = env->GetStringUTFChars(keyStr, NULL);
+        String8 key(keyChars);
+        env->ReleaseStringUTFChars(keyStr, keyChars);
+
+        int nkey =  strlen (key.string());
+
+        err = sqlite3_key(db, key.string(), nkey);
+        if (err != SQLITE_OK)
+        {
+            ALOGE("sqlite3_key failed: %d", err);
+            throw_sqlite3_exception_errcode(env, err, "Key error ! Count not Access db.");
+            return 0;
+        }
+
+
+    }
+
+#endif
+
     // Check that the database is really read/write when that is what we asked for.
-    if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
+    if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL))
+    {
         throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
         sqlite3_close(db);
         return 0;
@@ -143,7 +176,8 @@

     // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
     err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
-    if (err != SQLITE_OK) {
+    if (err != SQLITE_OK)
+     {
         throw_sqlite3_exception(env, db, "Could not set busy timeout");
         sqlite3_close(db);
         return 0;
@@ -151,7 +185,8 @@

     // Register custom Android functions.
     err = register_android_functions(db, UTF16_STORAGE);
-    if (err) {
+    if (err)
+    {
         throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
         sqlite3_close(db);
         return 0;
@@ -161,10 +196,12 @@
     SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);

     // Enable tracing and profiling if requested.
-    if (enableTrace) {
+    if (enableTrace)
+    {
         sqlite3_trace(db, &sqliteTraceCallback, connection);
     }
-    if (enableProfile) {
+    if (enableProfile)
+    {
         sqlite3_profile(db, &sqliteProfileCallback, connection);
     }

@@ -172,13 +209,17 @@
     return reinterpret_cast<jint>(connection);
 }

-static void nativeClose(JNIEnv* env, jclass clazz, jint connectionPtr) {
+static void nativeClose(JNIEnv* env, jclass clazz, jint connectionPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);

-    if (connection) {
+    if (connection)
+    {
+        sync();
         ALOGV("Closing connection %p", connection->db);
         int err = sqlite3_close(connection->db);
-        if (err != SQLITE_OK) {
+        if (err != SQLITE_OK)
+        {
             // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
             ALOGE("sqlite3_close(%p) failed: %d", connection->db, err);
             throw_sqlite3_exception(env, connection->db, "Count not close db.");
@@ -191,7 +232,8 @@

 // Called each time a custom function is evaluated.
 static void sqliteCustomFunctionCallback(sqlite3_context *context,
-        int argc, sqlite3_value **argv) {
+        int argc, sqlite3_value **argv)
+{
     JNIEnv* env = AndroidRuntime::getJNIEnv();

     // Get the callback function object.
@@ -235,7 +277,8 @@
 }

 // Called when a custom function is destroyed.
-static void sqliteCustomFunctionDestructor(void* data) {
+static void sqliteCustomFunctionDestructor(void* data)
+{
     jobject functionObjGlobal = reinterpret_cast<jobject>(data);

     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -243,7 +286,8 @@
 }

 static void nativeRegisterCustomFunction(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jobject functionObj) {
+        jobject functionObj)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);

     jstring nameStr = jstring(env->GetObjectField(
@@ -267,7 +311,8 @@
 }

 static void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jstring localeStr) {
+        jstring localeStr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);

     const char* locale = env->GetStringUTFChars(localeStr, NULL);
@@ -280,20 +325,25 @@
 }

 static jint nativePrepareStatement(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jstring sqlString) {
-    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
-
-    jsize sqlLength = env->GetStringLength(sqlString);
-    const jchar* sql = env->GetStringCritical(sqlString, NULL);
-    sqlite3_stmt* statement;
-    int err = sqlite3_prepare16_v2(connection->db,
-            sql, sqlLength * sizeof(jchar), &statement, NULL);
-    env->ReleaseStringCritical(sqlString, sql);
-
-    if (err != SQLITE_OK) {
-        // Error messages like 'near ")": syntax error' are not
-        // always helpful enough, so construct an error string that
-        // includes the query itself.
+        jstring sqlString)
+{
+SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+int err = -1 ;
+sqlite3_stmt* statement;
+
+    jsize sqlLength = env->GetStringLength(sqlString);
+    const jchar* sql = env->GetStringCritical(sqlString, NULL);
+
+    err = sqlite3_prepare16_v2(connection->db,
+            sql, sqlLength * sizeof(jchar), &statement, NULL);
+
+    env->ReleaseStringCritical(sqlString, sql);
+
+    if (err != SQLITE_OK)
+    {
+        // Error messages like 'near ")": syntax error' are not
+        // always helpful enough, so construct an error string that
+        // includes the query itself.
         const char *query = env->GetStringUTFChars(sqlString, NULL);
         char *message = (char*) malloc(strlen(query) + 50);
         if (message) {
@@ -311,7 +361,8 @@
 }

 static void nativeFinalizeStatement(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr) {
+        jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -323,7 +374,8 @@
 }

 static jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr) {
+        jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -331,7 +383,8 @@
 }

 static jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr) {
+        jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -339,7 +392,8 @@
 }

 static jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr) {
+        jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -347,7 +401,8 @@
 }

 static jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr, jint index) {
+        jint statementPtr, jint index)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -363,7 +418,8 @@
 }

 static void nativeBindNull(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr, jint index) {
+        jint statementPtr, jint index)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -374,7 +430,8 @@
 }

 static void nativeBindLong(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr, jint index, jlong value) {
+        jint statementPtr, jint index, jlong value)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -385,7 +442,8 @@
 }

 static void nativeBindDouble(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr, jint index, jdouble value) {
+        jint statementPtr, jint index, jdouble value)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -396,7 +454,8 @@
 }

 static void nativeBindString(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr, jint index, jstring valueString) {
+        jint statementPtr, jint index, jstring valueString)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -411,7 +470,8 @@
 }

 static void nativeBindBlob(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr, jint index, jbyteArray valueArray) {
+        jint statementPtr, jint index, jbyteArray valueArray)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -425,7 +485,8 @@
 }

 static void nativeResetStatementAndClearBindings(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr) {
+        jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -438,7 +499,8 @@
     }
 }

-static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
+static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement)
+{
     int err = sqlite3_step(statement);
     if (err == SQLITE_ROW) {
         throw_sqlite3_exception(env,
@@ -450,7 +512,8 @@
 }

 static void nativeExecute(JNIEnv* env, jclass clazz, jint connectionPtr,
-        jint statementPtr) {
+        jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -458,7 +521,8 @@
 }

 static jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz,
-        jint connectionPtr, jint statementPtr) {
+        jint connectionPtr, jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -467,7 +531,8 @@
 }

 static jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz,
-        jint connectionPtr, jint statementPtr) {
+        jint connectionPtr, jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -476,7 +541,8 @@
             ? sqlite3_last_insert_rowid(connection->db) : -1;
 }

-static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
+static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement)
+{
     int err = sqlite3_step(statement);
     if (err != SQLITE_ROW) {
         throw_sqlite3_exception(env, connection->db);
@@ -485,7 +551,8 @@
 }

 static jlong nativeExecuteForLong(JNIEnv* env, jclass clazz,
-        jint connectionPtr, jint statementPtr) {
+        jint connectionPtr, jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -497,7 +564,8 @@
 }

 static jstring nativeExecuteForString(JNIEnv* env, jclass clazz,
-        jint connectionPtr, jint statementPtr) {
+        jint connectionPtr, jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -512,7 +580,8 @@
     return NULL;
 }

-static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) {
+static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length)
+{
     int error = 0;
     int fd = ashmem_create_region(NULL, length);
     if (fd < 0) {
@@ -547,7 +616,8 @@
 }

 static jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz,
-        jint connectionPtr, jint statementPtr) {
+        jint connectionPtr, jint statementPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);

@@ -571,7 +641,8 @@
 };

 static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
-        sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
+        sqlite3_stmt* statement, int numColumns, int startPos, int addedRows)
+{
     // Allocate a new field directory for the row.
     status_t status = window->allocRow();
     if (status) {
@@ -665,7 +736,8 @@

 static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
         jint connectionPtr, jint statementPtr, jint windowPtr,
-        jint startPos, jint requiredPos, jboolean countAllRows) {
+        jint startPos, jint requiredPos, jboolean countAllRows)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
     CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
@@ -759,7 +831,8 @@
     return result;
 }

-static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jint connectionPtr) {
+static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jint connectionPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);

     int cur = -1;
@@ -768,13 +841,15 @@
     return cur;
 }

-static void nativeCancel(JNIEnv* env, jobject clazz, jint connectionPtr) {
+static void nativeCancel(JNIEnv* env, jobject clazz, jint connectionPtr)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     connection->canceled = true;
 }

 static void nativeResetCancel(JNIEnv* env, jobject clazz, jint connectionPtr,
-        jboolean cancelable) {
+        jboolean cancelable)
+{
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     connection->canceled = false;

@@ -787,10 +862,62 @@
 }


+#ifdef SQLITE_HAS_CODEC
+
+static jint nativeReKey(JNIEnv* env, jclass clazz, jint connectionPtr,jstring key)
+{
+SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+int err;
+int nkey;
+const char* key_str;
+
+    if (connection)
+    {
+        key_str = env->GetStringUTFChars(key, NULL);
+        nkey = strlen (key_str);
+
+        err = sqlite3_rekey(connection->db, key_str, nkey);
+        env->ReleaseStringUTFChars(key, key_str);
+
+        if (err != SQLITE_OK)
+        {
+            ALOGE("sqlite3_rekey(%p) failed: %d", connection->db, err);
+            throw_sqlite3_exception(env, connection->db, "Re Key error ! Count not Access db.");
+
+        //==== Try to close db.
+            err = sqlite3_close(connection->db);
+            if (err != SQLITE_OK)
+            {
+                ALOGE("sqlite3_close(%p) failed: %d", connection->db, err);
+                throw_sqlite3_exception(env, connection->db, "Count not close db.");
+                return 0;
+            }
+
+            delete connection;
+            return 0;
+
+        }
+        else
+            return reinterpret_cast<jint>(connection);
+    }
+
+    ALOGE("Sqlite DB Connection is fail.");
+    return 0;
+}
+
+#else
+
+static jint nativeReKey(JNIEnv* env, jclass clazz, jint connectionPtr,jstring key)
+{
+    return 0;
+}
+#endif
+
+
 static JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
-    { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)I",
+    { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;ZZ)I",
             (void*)nativeOpen },
     { "nativeClose", "(I)V",
             (void*)nativeClose },
@@ -842,6 +969,10 @@
             (void*)nativeCancel },
     { "nativeResetCancel", "(IZ)V",
             (void*)nativeResetCancel },
+#ifdef SQLITE_HAS_CODEC
+    { "nativeReKey", "(ILjava/lang/String;)I",
+            (void*)nativeReKey },
+#endif
 };

 #define FIND_CLASS(var, className) \



diff -Nura TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/jni/Android.mk TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/jni/Android.mk
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/frameworks/base/core/jni/Android.mk    2012-12-17 15:18:28.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/frameworks/base/core/jni/Android.mk    2013-06-13 10:13:15.811329249 +0800
@@ -1,9 +1,14 @@
+##
+##
+##
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)

 LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
 LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
 LOCAL_CFLAGS += -U__APPLE__
+LOCAL_CFLAGS += -DSQLITE_HAS_CODEC

 ifeq ($(TARGET_ARCH), arm)
     LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"



大功告成 ,並且可以讓簡單的 APP 開啟事先已經加密好的 database.db file .


PS. 上面內容會有錯誤(基於工作內容的關係 , 有些細節沒有說明 ) , 不過可以按照這樣的
      步驟修改 , 並且逐步 debug .... 即可.


2013年5月27日 星期一

測試 sqlite 加密

加密功能完成了 , 寫一個測試程式來試試看吧 !!

首先要說明 , 這個程式原作者是 Alvin , 我借用這個程式修改一下來測試 !!

這個程式會 Create /tmp/t01.db , 並且設定加密 key .
然後填寫一些固定的 data 到 db 中 , 並且dump , quary 等一些機本操作 !!
接著執行 rekey 功能 (移除 key ) , 如果不想移除 key 可以用 Ctrl + C 中斷 !!
然後用 cat 看看 t01.db 的內容 是否有加密 !!

執行完 rekey 後一樣有 dump , quary 功能  , 可以比對加密/ 沒加密是否有錯誤 !!
當然 rekey 後也可用 cat 看看 t01.db 的內容

增加方式如下:

A.增加一個資料夾 sql-test.並且建立 Andorid.mk file.


diff -Nuraw TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/Android.mk TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/Android.mk
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/Android.mk    1970-01-01 08:00:00.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/Android.mk    2013-05-27 13:46:53.090414327 +0800
@@ -0,0 +1,32 @@
+##
+##
+## Build test program
+##
+##
+
+
+ifeq ($(CONFIG_PRJ_RELASE_TEST),y)
+
+LOCAL_PATH:= $(call my-dir)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := sqlkey.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../dist
+
+LOCAL_SHARED_LIBRARIES := libsqlite
+
+LOCAL_CFLAGS += -I$(LOCAL_PATH) -DSQLITE_HAS_CODEC=1
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE := sqlkey
+
+include $(BUILD_EXECUTABLE)
+
+endif
+


B.建立一個 db.h , 這是程式程式要用 heard file.

diff -Nuraw TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/db.h TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/db.h
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/db.h    1970-01-01 08:00:00.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/db.h    2013-05-27 11:02:01.742571654 +0800
@@ -0,0 +1,38 @@
+#ifndef __DB_H__
+#define __DB_H__
+
+#include "i_basetype.h"
+#include <sqlite3.h>
+
+#define MAX_SQL_LEN         1024         //
+#define MAX_DB_CNT          50
+
+typedef struct {
+    sqlite3     *db;
+    SCHAR       *cmd;
+    SCHAR       *exe;
+    UINT        opt;
+    SINT        ret;
+    UINT        *width;
+
+    int         row;
+    int         col;
+    UINT        total;
+    FREE SCHAR  **result;
+    SCHAR       *errmsg;
+    SINT        (*callback)(void *data, int argc, char **argv, char **columnNames);
+    VOID        *callback_arg;
+} SQL_CMD;
+
+#define SQL_OPT_SHOW    0x01       // show result & message
+#define SQL_OPT_MFREE   0x80       // manually free
+
+
+extern sqlite3 *m_db;
+
+int sql_execx(SQL_CMD *sql, char *fmt, ...);
+void sql_freex(SQL_CMD *sql);
+sqlite3 *db_open(SCHAR* db_name);
+void db_close(sqlite3 *db);
+
+#endif // __DB_H__


C.建立 i_basetype.h , 主要定義一些基本的結構和資料 Type.


diff -Nuraw TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/i_basetype.h TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/i_basetype.h
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/i_basetype.h    1970-01-01 08:00:00.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/i_basetype.h    2013-05-27 11:01:46.815417060 +0800
@@ -0,0 +1,113 @@
+//
+#ifndef __I_BASETYPE_H__
+#define __I_BASETYPE_H__
+
+typedef  char               SCHAR;              // 8-bit
+typedef  short              SSHORT;             // 16-bit
+typedef  int                SINT;               // 32-bit
+typedef  long               SLONG;              // 32-bit
+typedef  long long          SLONGLONG;          // 64-bit
+/*
+typedef signed char         SCHAR;              // 8-bit
+typedef signed short        SSHORT;             // 16-bit
+typedef signed int          SINT;               // 32-bit
+typedef signed long         SLONG;              // 32-bit
+typedef signed long long    SLONGLONG;          // 64-bit
+*/
+
+typedef unsigned char       UCHAR;              // 8-bit
+typedef unsigned short      USHORT;             // 16-bit
+typedef unsigned int        UINT;               // 32-bit
+typedef unsigned long       ULONG;              // 32-bit
+typedef unsigned long long  ULONGLONG;          // 64-bit
+
+#ifndef __BASE_TYPE_DEFINED__
+#define __BASE_TYPE_DEFINED__
+
+typedef unsigned int        BOOL;               // 32-bit
+
+typedef unsigned char       UINT8;              // 8-bit
+typedef unsigned short      UINT16;             // 16-bit
+typedef unsigned int        UINT32;             // 32-bit
+typedef unsigned long long  UINT64;             // 64-bit
+
+typedef signed char         SINT8;              // 8-bit
+typedef signed short        SINT16;             // 16-bit
+typedef signed int          SINT32;             // 32-bit
+typedef signed long long    SINT64;             // 64-bit
+
+#endif // __BASE_TYPE_DEFINED__
+
+typedef void                VOID;               // 32-bit
+typedef float               FLOAT;              // 32-bit
+typedef double              DOUBLE;             // 64-bit
+
+typedef struct {
+    union {
+        SCHAR               c;
+        SSHORT              s;
+        SINT                i;
+        SLONG               l;
+        SLONGLONG           ll;
+        UCHAR               b;
+        USHORT              w;
+        UINT                u;
+        ULONG               q;
+        ULONGLONG           lq;
+        FLOAT               f;
+        DOUBLE              d;
+        VOID                *p;
+    } v;
+} VALUE; // 64-bit/8 bytes
+
+#ifndef IO
+    #define IO
+#endif
+#ifndef IN
+    #define IN
+#endif
+#ifndef OUT
+    #define OUT
+#endif
+
+#ifndef FREE
+    #define FREE
+#endif
+
+#ifndef TRUE
+    #define TRUE                            1
+#endif
+
+#ifndef FALSE
+    #define FALSE                           0
+#endif
+
+#ifndef MIN
+  #define MIN(x,y)                      ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+  #define MAX(x,y)                      ((x)>(y)?(x):(y))
+#endif
+
+#ifndef ABS
+    #define ABS(x)                      (((x)>=0)? (x): -(x))
+#endif
+
+#ifndef DIM
+  #define DIM(var,type)                 (sizeof(var)/sizeof(type))
+#endif
+
+#ifndef OFFS
+  #define OFFS(type,item)               ((UINT)&(((type*)0)->item))
+#endif
+
+#ifndef SIZE
+  #define SIZE(type,item)               (sizeof(((type*)0)->item))
+#endif
+
+#ifndef BITMASK
+    #define BITMASK(b)                  ((ULONG)0x01UL << (b))
+#endif
+
+#endif // __I_BASETYPE_H__


D. 主要程式.

diff -Nuraw TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/sqlkey.c TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/sqlkey.c
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/sql-test/sqlkey.c    1970-01-01 08:00:00.000000000 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/sql-test/sqlkey.c    2013-05-27 10:56:06.118859064 +0800
@@ -0,0 +1,346 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "db.h"
+#include <sqlite3.h>
+
+
+#define    DB_FILE     "/tmp/t01.db"
+
+//========================
+sqlite3 *m_db=NULL;
+
+int sql_execx(SQL_CMD *sql, char *fmt, ...)
+{
+    static char cmd[PATH_MAX];
+    int rc=0, sel=0;
+    va_list args;
+
+    if(m_db==NULL)
+    {
+        printf("database not opened.\n");
+        return(-100);
+    }
+    sql->db=m_db;
+    sql->exe=cmd;
+    sql->ret=0;
+    sql->row=0;
+    sql->col=0;
+    sql->total=0;
+    sql->result=NULL;
+    sql->errmsg=NULL;
+    //
+    va_start(args, fmt);
+    cmd[PATH_MAX - 1] = '\0';
+    sprintf(cmd, fmt, args);
+    va_end(args);
+
+    if(strncmp(cmd, "select", 6)==0)
+        sel=1;
+    if(sel)
+        rc = sqlite3_get_table(sql->db, cmd, &sql->result, &sql->row, &sql->col, &sql->errmsg);
+    else
+        rc = sqlite3_exec(sql->db, cmd, NULL /* callback */, NULL  /* callback_arg */, &sql->errmsg);
+    if(SQLITE_OK != rc)
+    {
+        if(sql->opt&SQL_OPT_SHOW)
+            printf("* SQL error! cmd='%s', err=%d (%s).\n", cmd, rc, sql->errmsg);
+        return(-rc);
+    }
+    if(sel)
+    {
+        int r, c;
+
+        rc=sql->row;
+        if(sql->opt&SQL_OPT_SHOW)
+        {
+            printf("--------------------------------------\n");
+            printf("SELECT: row=%d, col=%d, rc=%d.\n", sql->row, sql->col, rc);
+            printf("--------------------------------------\n");
+            for(r=0; r<=sql->row; r++)
+            {
+                for(c=0; c<sql->col; c++)
+                    printf("%-*s", (sql->width? sql->width[c]: 16), sql->result[(r*sql->col)+c]);
+                if(sql->row)
+                    printf("\n");
+            }
+            printf("--------------------------------------\n");
+        }
+        if((sql->opt&SQL_OPT_MFREE)==0)
+        {
+            sqlite3_free_table(sql->result);
+            sql->result=NULL;
+        }
+    }
+    return(sql->ret=rc);
+}
+
+void sql_freex(SQL_CMD *sql)
+{
+    if(sql->result)
+    {
+        sqlite3_free_table(sql->result);
+        sql->result=NULL;
+    }
+}
+
+sqlite3 *db_open(char* db_name)
+{
+    int rc=0;
+    sqlite3 *db=NULL;
+
+    //open a database, create it if doesn't exist.
+    if((rc=sqlite3_open(db_name, &db))!=SQLITE_OK)
+    {
+        printf("sqlite3_open() failed, db='%s', err=%d (%s).\n", db_name, rc, sqlite3_errmsg(db));
+        return(NULL);
+    }
+
+    m_db = db;
+    return(db);
+}
+
+void db_close(sqlite3 *db)
+{
+    if(db)
+        sqlite3_close(db);
+
+}
+
+void ap_initial(void)
+{
+    if((m_db=db_open(DB_FILE))==NULL)
+        printf("db_open() failed, file=%s\n", DB_FILE);
+}
+
+void ap_shutdown(void)
+{
+    if(m_db)
+        db_close(m_db);
+}
+
+int main(int argc, char* argv[])
+{
+    int rc=0;
+
+    SQL_CMD sql;
+
+    printf("=== SQLite test utility v0.1 - Alvin, 2009/03/08 ===\n");
+    ap_initial();
+
+    sqlite3_key(m_db,"1q2w3e4r",8);
+
+
+    memset(&sql, 0, sizeof(sql));
+    sql.db = m_db;
+    sql.opt = SQL_OPT_SHOW;
+
+/*
+create table dict_tbl(vocab text, sentence text, name text);
+*/
+
+    printf("Testing Create Table\n");
+    getchar();
+
+    if((rc=sql_execx(&sql, "create table dict_tbl(vocab text, sentence text, name text)"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+    printf("=== Done. ===\n");
+
+    printf("Testing Insert data\n");
+    getchar();
+
+
+
+//insert into dict_tbl values('a', 'This is an apple.', '陳奕迅先生');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('a', 'This is an apple.', '陳奕迅先生')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('book', 'This is a book.', '陳曉東先生');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('book', 'This is a book.', '陳曉東先生')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('he', 'He is a good student.', '張宇先生');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('he', 'He is a good student.', '張宇先生')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('let', "Let's go for shopping.", '張信哲先生');
+
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('let', 'Let-s go for shopping.','張信哲先生')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('sample', 'The sample is very easy.', '張學友先生');
+
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('sample', 'The sample is very easy.', '張學友先生')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('she', 'She is more beautiful than you.', '范瑋琪小姐');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('she', 'She is more beautiful than you.', '范瑋琪小姐')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('that', 'That is my desk.', '陳珊妮小姐');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('that', 'That is my desk.', '陳珊妮小姐')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+//insert into dict_tbl values('this', 'This is your sample.', '張惠妹小姐');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('this', 'This is your sample.', '張惠妹小姐')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+//insert into dict_tbl values('tomorrow', 'I will go to USA tomorrow.', '陳慧琳小姐');
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('tomorrow', 'I will go to USA tomorrow.', '陳慧琳小姐')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+//insert into dict_tbl values('you', 'You are so beautiful.', '張清芳小姐');
+
+    if((rc=sql_execx(&sql, "insert into dict_tbl values('you', 'You are so beautiful.', '張清芳小姐')"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+    printf("=== Done. ===\n");
+
+    printf("Testing dump data \n");
+    getchar();
+
+    if((rc=sql_execx(&sql, "select * from dict_tbl"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+    printf("=== Done. ===\n");
+
+    printf("Testing quary '*you*' data \n");
+    getchar();
+
+//select sentence from dict_tbl where sentence like '%you%';
+    if((rc=sql_execx(&sql, "select sentence from dict_tbl where sentence like '%%you%%'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+    printf("Testing quary '*is*you*' data \n");
+    getchar();
+
+//select sentence from dict_tbl where sentence like '%is%you%';
+    if((rc=sql_execx(&sql, "select sentence from dict_tbl where sentence like \"%%is%%you%%\""))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+
+    printf("Testing quary '*is*a*' data \n");
+    getchar();
+
+//select sentence from dict_tbl where sentence like '%is%a%';
+    if((rc=sql_execx(&sql, "select sentence from dict_tbl where sentence like '%%is%%a%%'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+    printf("=== Done. ===\n");
+    printf("Testing rekey\n");
+    getchar();
+
+    sqlite3_rekey(m_db,"",0);
+
+    printf("=== Done. ===\n");
+    printf("Testing dump data after rekey\n");
+    getchar();
+
+
+    if((rc=sql_execx(&sql, "select * from dict_tbl"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+    printf("=== Done. ===\n");
+
+    printf("Testing quary '陳*' and sentence like '*book*' data \n");
+    getchar();
+
+//select * from dict_tbl where name like '陳%' and sentence like '%book%';
+    if((rc=sql_execx(&sql, "select * from dict_tbl where name like '陳%%' and sentence like '%%book%%'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+
+    printf("Testing quary '張*' data \n");
+    getchar();
+
+//select * from dict_tbl where name like '張%';
+    if((rc=sql_execx(&sql, "select * from dict_tbl where name like '張%%'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+
+    printf("Testing quary '陳*先生' data \n");
+    getchar();
+
+//select * from dict_tbl where name like '陳%先生';
+    if((rc=sql_execx(&sql, "select * from dict_tbl where name like '陳%%先生'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+
+    printf("Testing quary '張*小姐' data \n");
+    getchar();
+//select * from dict_tbl where name like '張%小姐';
+    if((rc=sql_execx(&sql, "select * from dict_tbl where name like '張%%小姐'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+
+    printf("Testing quary '*小姐' data \n");
+    getchar();
+
+//select * from dict_tbl where name like '%小姐';
+    if((rc=sql_execx(&sql, "select * from dict_tbl where name like '%%小姐'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+
+    printf("Testing quary '*先生' data \n");
+    getchar();
+
+//select * from dict_tbl where name like '%先生'; --> error
+
+    if((rc=sql_execx(&sql, "select * from dict_tbl where name like '%先生'"))<0)
+    {
+        printf("* SQL error, cmd=%s, rc=%d (%s).\n", sql.exe, rc, sql.errmsg);
+    }
+
+    printf("=== Done. ===\n");
+    getchar();
+
+    sql_freex(&sql);
+    ap_shutdown();
+
+    return 0;
+}




結果  ...... 正確沒有問題 , 打完收工 .......