2010年3月4日 星期四

HTC Tattoo 建立自製的 Boot Image

Android 的 Boot Image 是用來載入 kernel 並且建立 root file system 的 image。它是一個非常重要的檔案,因為,所以的載入程序都在 Boot Image 之中。

Android 的 Image 共有三個:boot image, system image, data image。當然,有些人可能會說,還有 recovery image,它是在出問題的時候,用來覆原的 image,大致上,recovery image 會是 boot image + 一部份 system image。

Android Boot Image 是一個 android 自定的格式,它可以分成 2K 的 header + kernel + ramdisk + second stage。

原則上來說,這些資訊都可以從 android 的網站中查到。這篇文章的重點將放在,如何建立給 tattoo 用的 build image。

自從 tattoo 可以取得 root 權限後,這幾天福克斯花了些時間想找出在 tattoo 上把應用程式放到 sd 卡的方法。要達到這項目標就一定要做出自己的 boot image。

Boot Image 的製作可以依照這個 wiki 進行,它看起來非常簡單,尤其是作者已經寫了 split_bootimg,unpack 及 repack 的 perl 檔。大家可以依照這個 wiki 進行 boot image 的設計。

老實說,最困難的地方不是修改或是 unpack,而是 repack。跟據 mainfram3 於 XDA 上的文章,由於 tattoo 的 boot image 的 base offset 與其它的 boot image 不同,所以,wiki 的 unpack script 是沒辦法建立出 tattoo 可以讀出的檔案。

福克斯的作法就是用 split_bootimg 的方式,再使用 mkbootfs + mkbootimg 的方式來將它包裝起來。它的使用方式如下:

mkbootfs {ramdisk_folder} | gzip > {ramdisk_output}.gz

再使用

mkbootimg --base 0x2E00000 --cmdline "cmdline: no_console_suspend=1 console=null" --kernel {kernel_file} --ramdisk {ramdisk_output}.gz -o your_boot_image.img

其中最重要的部份就是 --0x2E00000,福克斯目前也不知道為什麼是這樣設計,但是,透過 HEX editor 的方式,可以從 tattoo 的 boot image 中看出來。

最後,大家可能會遇到另一個問題: where is mkbootfs and mkbootimg??? 當初福克斯在做的時候,也遇到這個問題。其實,這兩個檔案需要下載完整的 android source code,然後再將它 compile 起來,會在 output/host/ 中發現。這兩個檔案,其實可以用 google 來找到,只是,到目前為止,福克斯只找到 mac os 跟 linux 兩種版本(linux 的是福克斯自己編釋出來的)。致於,windows 版,可能要大家自行編釋了。

2010年3月2日 星期二

HTC Tattoo 誤刪檔案以致無法更新之問題

自動 HTC Tattoo 可以取得 root 權限後,漸漸開始有人刪除 /system/app 中的應用程式(福克斯就是其中之一)。

剛好,最近,HTC 開始發送 OTA 的更新,以將台灣版本從 1.67.921.22 一路昇級到 1.67.921.24(一次要更新兩個)。

福克斯剛好就是先刪檔,然後導致更新時,因為找不到檔案,而無法更新。所以,福克斯就將 HTC Tattoo 的更新檔打開來研究。

如果大家也有類似的問題,可以用下面的方式來解決:

1. 跟朋友(一定要有 Tattoo 外加是同一個版本)要已經刪除的檔案,HTC 的檔案有分成:apk 跟 odex兩種。記得,兩種都要 copy。
2. 將 apk 及 odex 複製進 /system/app。
3. 如果複製進去後, Tattoo 變成全黑,而且無法使用的話,將複製進去的 apk 給刪除,再重新開機。
4. 重新下載更新檔及安裝更新。

福克斯從星期一開始進行測試,後來一路到星期一晚上,從朋友拿取得正確的檔案,才能更新。

老實說,這次的更新雖然並不是很重要的更新,不過它卻讓無線網路變的比較穩定。

2010年3月1日 星期一

HTC Tattoo 取得 root 權限?? Do I Need It??

Rooting HTC Tattoo 這個主題從 Tattoo 一出廠就一直燒到現在。最近(二月二十五日), XDA 的大神們透過 kernel 的一個 bug ,已經成功取得了 root 的權限。福克斯也於 2 月 26 日成功地取得 root 權限

相信各位可以透過 google 找到許多的方法來破解。原本,福克斯想自己寫一篇如何取得 root 權限的文章。但是,google 了一下,居然一堆人已經寫了,而且才短短兩天,就能在 google 的前幾筆找到正確的文章。

福克斯使用的方式和 lRabbit 相同,網址:http://abev66.blogspot.com/2010/02/rooting-tattoo.html。lRabbit 整理的非常清楚,而且也加註了許多警語:變磚 <== 最可怕的項目

老實說,福克斯並不認為 Tattoo 會變磚,只是,你可能會需要許多的時間及知識去把它給救回來就是了。

唉,為什麼福克斯要語重心長地討論這個問題呢?因為,福克斯不小心把一些檔案給砍掉,然後,剛好又遇到 2 月 27 日的 Tattoo update,導致 update 的時候,因為那些被砍掉的檔案,所以讓 update-script 的 check 跑不過....看來福克斯的 Tattoo 只能活在 1.67.921.22 版本之中了....看來福克斯也只能自我感覺良好了....唉...

這只能用一個字來形容。

到底取得 root 權限有什麼好處,為什麼會讓大家(其實是福克斯比較衝啦)這樣前仆後繼地取得 root 權限。

一般來說,root 權限就是像 Windows 中的 Administrator 帳號一樣。很多 XDA 的大神們都認為:為什麼我買一台手機,卻不可以得到手機的完整理管權?例如,我不能把某些不喜歡的應用程式給砍掉(例如 KKBOX, 股市報價...等針對某些電信業者所附加的應用程式)。

相對地,當我們能夠得到完整的管理權的時候,手機製造商會擔心我們不小心把不該砍的程式給砍掉(就像福克斯一樣,手太賤把 HTC Plurk 跟 HTC Twitter 給砍掉)。

所以,從這個角度來看,其實拿不到完整的管理權限是件不錯的事。

不過呢,當我們取得 root 權限後,可以:
1. 安裝不同版本的 Android,讓 Tattoo 不再只是 HTC Sense + Android 1.6,能直接跳級到 2.1。(目前還沒有 2.1 的 ROM,不過已經有其它 1.6 的 ROM 了)
2. 安裝 Bluetooth 的 ROM,讓 Tattoo 不再只能用 Bluetooth 講電話,還能傳檔及收檔。
3. 安裝 App2SD,讓 Tattoo 的儲存空間不再只有可憐的 90M,能要幾 G 就幾 G。(這部份還需要 XDA 的大神們找機會才行)
4. 安裝 Windows Mobile 的 ROM,讓 Tattoo 不再只是 Android 手機。
5. 把一些不喜歡的程式給砍掉,就像福克斯這樣把一些看不順眼的東西給砍了。
6. 滿足自己的虛榮心 => 媽,我已經拿到 root 權限了哦....

對福克斯來說,真正有吸引力的是 1, 2, 3 項,尤其是第 2 項。因為:
1. Bluetooth 沒辦法傳檔,這實在丟臉了吧。當然,Android 1.6 版會這樣設計,Google 已經解釋到不能解釋了。不過,不能傳檔就是不能傳檔,再怎麼解釋還是沒用的。
2. 有使用 Windows Mobile 的朋友們都覺得 怎麼會有作業系統不讓我們在 SD 卡上執行程式。是的,這也是件非常不合理的事。

所以,這也就是許多很衝的人瘋狂地取得 root 權限的原因。

話說回來,只要各位願意等上面的 1, 2, 3 項優點,其實 HTC 都有可能會幫我們解決掉。只是不知道要等到什麼時候就是了。

最後,福克斯還是請各位有能力或有心想要取得 root 權限的人們:一定要三思啊。對那些已經取得 root 權限的人,記得刪檔案之前,記得要備份

2010年2月26日 星期五

使用 NetBeans CND 來做 Microsoft Windows Message Hook

最近,福克斯的同事需要設計一個 Windows 的 Message Hook。但是,福克斯及同事們都是採用 Linux + NetBeans 的開發環境,而且又不大熟悉 Microsoft Visual C++ 的開發方式。因此,福克斯只好研究如何使用 NetBeans 的 CND 來開發 Microsoft Windows Message Hook。

1. Message Hook

Windows 的 Message Hook 是用來攔截 Windows 所有事件的方式。這個功能,可以用來設計病毒,或是惡搞別的應用程式。所以,在設計的時候,必須非常小心,不然會需要重新開機很多次。

開發 Message Hook 的程式時,必須要注意到: Windows 的 program loader 會將 message hook 的程式(它會是 dynamic linking library)連結到正在執行的 process,並呼叫 message hook 的 callback。正因為 callback 必須連結到正在執行的 process,它一定要是 dynamic linking library。所以,這次的程式會包含:a. message hook callback library, b. 專門接收事件的應用程式。

福克斯知道,這件事與 Linux 的 shared library 運作方式不同。這是因為, Windows 是採用 message queue 的運作方式來傳輸事件(在 Windows 叫 message)。

2. Project 的設計

這次的開發,其實與傳統的 NetBeans 開發 Windows 應用程式非常相似,建立一個執行檔專案外加一個 dynamic linking library (DLL) 專案、及一個應用程式的專案。另外,為了方便起見,福克斯決定不使用 SendMessage 的方式將資料轉輸到另一個 process 之中。而是使用 shared memory 的方式來做資料交換。

3. NetBeans Project 的設定

Project 的設定大致上與傳統 NetBeans CND 的方式一樣,只是在 DLL 的部份,必須要選擇 Application,並於 linker 的 additional options 輸入 -mdll 用來產生 DLL。這個設定如下:


4. 程式內容

程式碼的解說,福克斯僅以程式為主,一般的宣告請參考原始碼。

4.a DLL - Library Entrypoint

Windows 的 library 可以有自己的 entrypoint,它就像 Linux 的 so 可以有 OnLoad 類似。但是,不同的地方是,這個 entrypoint 會在 DLL 被連結到 process 及 thread 時候被呼叫到。這邊要特別注意是: Message Hook 的 library 會被連結到多個 process 之中,所以這個 function 會被連結到很多個 process 之中。所以,這個 function 需要建立一個 cross process 的共享記憶體,並將不同 process 的 message 的資料放到這個共享記憶體之中。
/**
* the entry point of this dll
* */

BOOL WINAPI DllMain(HINSTANCE hInst, ULONG uReason, LPVOID lpReserved) {
switch (uReason) {
//create or link to the shared memory
case DLL_PROCESS_ATTACH:
{
//create the shared memory
g_hMappedHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeof (GlobalSharedData),
"NetBeans_MessageHookSharedMemory");
//link the shared memory to g_pData which belongs to the current process.
g_pData = (GlobalSharedData*) MapViewOfFile(g_hMappedHandle,
FILE_MAP_WRITE, 0, 0, 0);
g_bReady = (NULL != g_hMappedHandle) && (NULL != g_pData) &&
(GetLastError() != ERROR_ALREADY_EXISTS);

if (g_bReady) {
//initialize the global shared data
g_pData->instance = hInst;
g_pData->hook = NULL;
g_pData->eventCount = 0;
}
//we don't care the thread switch, disable it.
DisableThreadLibraryCalls(hInst);
break;
}
case DLL_PROCESS_DETACH:
{
//remove the shared memory link.
CloseHandle(g_hMappedHandle);
break;
}
}

return TRUE;
}
4.b DLL - APIs

這個部份比較單純,就是提供一組 API 讓另一個專案呼叫。這邊較特別的是,HHOOK 必需被儲存到共享的記憶體之中,因為它之後會被呼叫到。

/**
* to remove the message hook
* */

BOOL StopHook() {
//remove the windows hook
BOOL bResult = UnhookWindowsHookEx(g_pData->hook);
//clear the data
g_pData->hook = NULL;
g_pData->instance = NULL;
return bResult;
}

/**
* to get the record message
* */

void GetMessageString(char* buf) {
//copy the strBuffer to cb
strcpy(buf, g_pData->strBuffer);
}

/**
* to hook the message hook
* */

BOOL StartHook() {
if (g_bReady) {
//hook the windows hook
g_pData->hook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) HookProc,
g_pData->instance, 0);
//if null is returned, it fails.
return NULL != g_pData->hook;
} else {
//no shared memory linked, we don't need to do anything.
return false;
}
}

/**
* the total event count
* */

int GetEventCount() {
return g_pData->eventCount;
}
4.c DLL - Message Hook Callback

因為這邊福克斯是以 Keyboard callback 當成範例,所以下面是將 keyboard message 中的資料轉換成字串,然後放到暫存的字串空間之中,並將 count 加 1 ,以等待另一個專案的程式來將暫存的字串拿走。這邊比較特別的地方是,這個 function 會被不同 process 呼叫到,所以GetModulebaseName() 不一定是 HookMain,而是正在接收 message 的 process name。

/**
* the hook proc for receiving all keyboard events
* */
LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam) {

//get process name
char strProcName[_MAX_FNAME];
GetModuleBaseName(GetCurrentProcess(), NULL, strProcName, sizeof (strProcName));

//put data to buffer
sprintf(g_pData->strBuffer, "data #%d, %s, lParam: %u, wParam: %u, code: %d\n",
(unsigned int) g_pData->eventCount, strProcName, lParam, wParam, nCode);
g_pData->eventCount++;
//we always call next hook to process this message
return CallNextHookEx(g_pData->hook, nCode, wParam, lParam);
}
嚴格來說,這樣的設計是一個錯誤的設計。因為,兩個 process 在執行的時候,它們執行的先後順序是無法控制。所以,正確的作法會是透過 send message 的方式讓其它的 process 收到資料。

福克斯會設計這個範例的最主要原因是,先前福克斯的同事們大多僅以設計 single process 的程式,而較少 inter-process communication 的部份,以共享記憶體的方式,較容易被人所接受。當這部份的原理了解後,再去使用 send message 將會較為容易了(呵,其實正確的說法是,會寫 Windows 程式的人一定會用 send message,但不一定會用 inter-process 的共享記憶體)。

4.d HookMain - WinMain

WinMain 是 Windows 主程式的進入點,它跟 main function 是一樣的。所以它的寫法與傳統的方式完全相同。

這邊的程式如 4.c 所提到,它只是個錯誤範例。它會每隔 1ms 去檢查 event count 是否有變化,如果有變化就把文字列到 console 之中。

/**
* the main function in windows
* */

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {

//the buffer for message text
char tempBuffer[256] = "Empty";
//create the message hook
StartHook();

int nCurrentMessageCount = 0;
int nLastMessageCount = 0;

DWORD nStartTickCount = GetTickCount();
DWORD nDiff = 0;
//5 seconds
while (nDiff < 5000) {
//get the message count
nCurrentMessageCount = GetEventCount();
if (nCurrentMessageCount != nLastMessageCount) {
//copy and print the message from the dll
GetMessageString(tempBuffer);
printf("%s", tempBuffer);
nLastMessageCount = nCurrentMessageCount;
} else {
Sleep(1);
}
nDiff = GetTickCount() - nStartTickCount;
}
//print the total message count
printf("Event Count: %d\n", nLastMessageCount);
//remove the message hook.
StopHook();
return 0;
}
5. 執行畫面與程式

完整的執行畫面如下:

程式的原始碼可於此處下載




2010年1月5日 星期二

How to Configure Your NetBeans for ARM Cross Compiling

It is important for an embedded programmer to have a good IDE with cross compiling ability. The eclipse can do this, and NetBeans also can do.

The configuration procedure of NetBeans to support ARM cross compiling is simple:

1. configure tool chain

You can configure the tool chain of NetBeans in [Tools/Options] menu item. In Options panel, the tool chain setting can be found at C/C++ tab, like the following image.




To create a tool chain setting, we need to press "Add" button and choose the root directory. It is very important to know that the root directory is the directory where as, gcc, g++ exist. So, in this case we choose "/usr/local/armeabi/bin".

2. configure project to using ARM tool chain

After the configuration of tool chain, we need to configure the NetBeans project to use this tool chain. To do this, we can open the NetBeans project properties by right-click it, choose "build" item and select the created tool chain item at "Tool Collection" combo box.


3. configure include and linker

To configure including and linking directory is the important thing while compiling C/C++ projects. There are lots of ways to do so. In this doc, we use absolute path to configure them as the following images:




While everything is done, it is easy to compile your project into ARM environment.

2009年12月2日 星期三

Brightness Calculator


The calculation of brightness is simple to do on single pixel. But there is no widget or tool for calculation of the average brightness of a photo. So, I wrote a simple tool for average brightness calculation, looking like as following:


The usage is simple, just clicking the "Add Files" button to pick a photo that Java supports and getting the average brightness of the photo in the table.

The link is here.

2009年6月8日 星期一

SDL on PSP

The correct method to set pixel value in a SDL_Surface is to use PixelFormat.Rshift, Gshift, Bshift, Ashift:

(*target32) = (r <<image->format->Rshift) |
(g <<image->format->Gshift) |
(b <<image->format->Bshift) |
(0x00 <<image->format->Ashift);