目前 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月27日 星期四
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 .... 即可.
加密就是為了不讓其他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;
+}
結果 ...... 正確沒有問題 , 打完收工 .......
首先要說明 , 這個程式原作者是 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;
+}
結果 ...... 正確沒有問題 , 打完收工 .......
訂閱:
意見 (Atom)