在介紹如何 debug 之前,首先必須知道的是,目前的系統到底有沒有記憶體洩漏?以下先介紹幾個常用的記憶體觀察法:

  • cat /proc/meminfo      // 粗略的觀察目前記憶體的種類以及各個種類的大小
  • ps                             // 觀察每個 process 目前記憶體使用的情況 
  • top                            // 看看前幾個記憶體使用最多的 process 是哪些
  • dumpsys meminfo      // Android 特有的指令,有更多的資訊







方法1 Memory Analyzer :

這個方法必須配合 Eclipse 使用,因為 Memory Analyzer (MAT) 是 Eclipse 的一個 Plugin。
  1. 第一個步驟當然是安裝 MAT,安裝得方法有許多種,你可以下載MemoryAnalyzer-1.0.1.201008091353.zip,解開到Plugins,或者在Eclipse上點選 Help --> Install New Software... --> Add,然後在 Name 輸入 Memory Analyzer ,在 Location 輸入 http://download.eclipse.org/mat/1.0/update-site/ ,如圖所示:
    按下 OK,之後要選擇安裝 Plugin 完成安裝程序。

  2. 一如往常的執行你想要 debug 的 Android 程式,然後透過進入 shell 裡面檢查 /data/misc/ 這個目錄是否有可讀寫的權限,因為我們等一下會 dump file 到這個目錄。另外,也可以簡單的把他的權限設成 777:
    adb shell
    chmod 777 /data/misc/
    

  3. 接下來執行程式到你認為會產生 leak 的地方,來回多執行幾次,然後利用 kill 這個指令送信號 SIGUSR1 (-10) 給你的 process (可以透過 ps 查看 Process ID),假設你要 debug "com.test.debug" 這個 process :
    ps
    ...
    PID UID       VSZ  Stat Command
    100 1000   255255    S  com.test.debug
    ...
    
    kill -10 100
    

  4. 你可以透過 logcat 來確認你的 process 有沒有收到 signal:
    logcat &
    

    如果看到類似如下的訊息表示有收到:
    I/dalvikvm(  236): threadid=3: reacting to signal 10
    I/dalvikvm(  236): SIGUSR1 forcing GC and HPROF dump
    I/dalvikvm(  236): hprof: dumping VM heap to "/data/misc/heap-dump-tm1291081439-pid100.hprof-hptemp".
    I/dalvikvm(  236): hprof: dumping heap strings to "/data/misc/heap-dump-tm1291081439-pid100.hprof".
    I/dalvikvm(  236): hprof: heap dump completed, temp file removed
    D/dalvikvm(  236): GC_HPROF_DUMP_HEAP freed 585 objects / 60000 bytes in 10595ms
    

    查看一下 /data/misc/ 目錄應該可以看到 heap-dump-tm1291081439-pid100.hprof:
    ls /data/misc/
    ...
    heap-dump-tm1291081439-pid100.hprof
    ...
    

  5. 離開 shell
    exit
    

    透過 adb pull 把這個檔案抓下來。
    adb pull /data/misc/heap-dump-tm1291081439-pid100.hprof
    

  6. 透過 hprof-conv 把剛剛抓下來的檔案轉換成 Memory Analyzer 認識的格式:
    hprof-conv heap-dump-tm1291081439-pid100.hprof debug.hprof
    

  7. 開啟 Eclipse,點選 Window --> Open Perspective --> Other... ,然後選擇 Memory Analyer。

  8. 點選 File --> Open Heap Dump... ,然後選擇剛剛轉換過的檔案 (此例為 debug.hprof)。接著會出現一個對話框,詢問你想產生什麼樣的報告,如下圖:
    此時我們的目的是偵測 memory leak,所以自然是選擇 Leak Suspects Report,按下 Finish 後,就會產生一個報告,告訴你可疑的地方。是不是很棒呢!


方法2 libc_debug.so : 

這個方法基本上是將 libc.so 換成 libc_debug.so 利用 libc_debug.so 提供多項偵錯的功能來查看記事體是否被不當的使用。

  1. 將 /system/lib/libc.so 替換成 /system/lib/libc_debug.so
  2. 重啟系統 adb shell reboot 
  3. adb shell setprop libc.debug.malloc 1" (or 5, or 10 for slightly different behaviors)
  4. 新增 "native=true" 到你的 ~/.android/ddms.cfg 檔案中
  5. 啟動 stand-alone 版的 DDMS. 接著你應該會看到有 "Native Heap" tab 出現,切到這個頁面後就可以 native memory 的使用情況。


方法3 c/c++ debugger : 

利用c/c++ debugger 來協助 debug c/c++ 層的 memory leak,接下的例子會使用 dmalloc 來 debug JNI native library.

  1. 先到 dmalloc 的官方網站 http://www.dmalloc.com 下載 source code。
  2. 交叉編譯 dmalloc,我個人是偏好用 Android NDK 來編譯,不過在這之前必須要先產生原本的 Makefile 然後照著 Makefile 來產生 Android.mk
    1. 執行 configure
      ./configure --prefix=/arm-linux/ --enable-cxx --enable-threads
      
      其中/arm-linux/是隨便指定的路徑,反正我們只是想要參考 Makefile。
    2. 參考 Makefile,轉換成 Android.mk
    3. 執行 ndk-build 來編譯 dmalloc
  3. 因為我們是要 debug JNI 的 native library 所以沒辦法透過一般的設定環境變倏地方法來指定 debug options:
    DMALLOC_OPTIONS=debug=0x4e48503,inter=100,log=/sdcard/dmalloc.%p
    export DMALLOC_OPTIONS
    

    必須自行在程式進入點指定 debug option,以 JNI 為例,可以利用 JNI_OnLoad() 當作是進入點,此外,離開的時候也必須關閉:
    #include "dmalloc.h"
    
    JNIEXPORT jint JNICALL JNI_OnLoad (
    ) {
        dmalloc_debug_setup ("debug=0x4e48503,inter=100,log=/sdcard/dmalloc.%p");
    }
    
    JNIEXPORT void JNICALL JNI_OnUnLoad (
    ) {
        dmalloc_shutdown ();
    }
    

    然後利用 dmalloc_mark() 與 dmalloc_log_changed() 來標記要偵錯的區段,下面我們以一個 JNI function 為例,故意造成 memory leak:
    unsigned long mark;
    
    JNIEXPORT void JNICALL JNI_com_example_debug_Test (
        JNIEnv* env,
        jobject thisArg
    ) {
        // Mark the start of debug
        mark = dmalloc_mark();
    
        // Leak memory 1000 bytes.
        char* leak = (char*) malloc (1000);
    
        // log unfreed pointers that have been added to
        // the heap since mark
        dmalloc_log_changed (
            mark,
            1,    // log unfreed pointers
            0,    // do not log freed pointers
            1     // log each pnt otherwise summary
        );
    }
    

    一旦這個 function 被呼叫,就會在 /sdcard/ 目錄下產生類似 dmalloc.1000 (副檔名是這個process 的 PID),然後裡面就會告訴你那一行發生 memory leak了。
    948436802: 1: Dmalloc version '5.5.2' from 'http://dmalloc.com/'
    948436802: 1: flags = 0x4e48503, logfile 'logfile'
    948436802: 1: interval = 100, addr = 0, seen # = 0, limit = 0
    948436802: 1: starting time = 948436802
    948436802: 1: process pid = 1000
    ...
    

<有背景音樂,請打開喇叭,音樂檔很大,請耐心等候>

好久以前曾經幫同事 Roger 做過婚禮記錄,但這一些記錄也隨著之前發表過的網站關閉而消失了,前陣子 Roger 父親的事情讓我感慨良多,藉著今天是 Roger 的生日,也順便把這些照片再做一番整理,也對希望 Roger 的父親能夠在天堂裡保佑我們,以馬內利。

出發去迎娶之前先拜祭家裡的祖先,祖先們啊, Roger 已經長大囉!今天就要娶媳婦過門了,請你們要好好保佑他...
↘


傳統的習俗還是要遵守的...
↘


Roger 拿著漂亮的捧花要準備出發囉!ㄟㄟ...少年耶,你笑得很僵耶!是很緊張吧!有我在免驚啦!...呵呵...^^
↘


出發前郵差先生還送來一封信,有幸福的預感喔!...^^
↘


Roger 的人生大事,父親不敢大意,在臨行前不忘再三叮嚀...
↘



想見到新娘哪有這麼容易啊?好姊妹當然要考考這位新郎官啦!Roger 說時遲那時快立刻掏出放在褲襠的..."紅包"...嘿嘿...還好我事先有準備,這下應該搞定了吧!
↘


嗯...紅包這招是不錯,不過,為了姊妹的「性福」,體能考驗還是要來一下啦!不是猛龍不過江,看我 Roger 輕鬆過關,嘿嘿...俺可是有練過的喔!...^^
↘


通過重重的考驗終於見到新娘啦! Rita 看起來好高興喔!不過我在一旁觀察到 Rita 父親的神情似乎有一些感傷,人家說:「女兒是父親前世的情人」真的一點也沒錯...女兒要嫁人總是捨不得的。
↘


拜別女方家長
↘





現場瀰漫著一種既喜氣又感傷的氣氛,我從 Rita 跟他父親的互動雖然不多但是卻可以看出他們的感情很好...
↘


這時候 Roger 機警的安撫丈母娘的情緒,這一招果然讓丈母娘放心許多...「師奶殺手」Roger 果然不是浪得虛名喔!呵呵...^^
↘


Rita 看著窗外的神情好美啊!就像一個美麗的「天使」(這也是我選這首背景音樂的原因)。看著窗外似乎也看到了未來,而 Roger 你應該知道吧!你就是她的未來...
↘


傳統的習俗是新娘出發前要把扇子丟掉...
↘


到新郎家囉!下車前要先摸個橘子,有吉利的意思喔!
↘


過火盆跟採瓦片也是一種招福的習俗。
↘


祭祖,啟稟祖先家裡今後將多一個成員囉,請祖先好好保佑葉家的媳婦。
↘


新娘給長輩奉茶啦!這也是古禮之一喔!
↘


看長輩笑得合不攏嘴...呵呵...
↘


來場景換到了新竹的勝利堂,接下來就是基督教的結婚儀式了。
↘


這位風度翩翩的帥哥就是新郎耶,一度以為是瓊瑤劇裡面的男主角呢...帥氣指數破表...呵呵...
↘


花童、伴娘跟新娘依序出場...
↘


牧師正在祝福這對新人,牧師口才很好,現場氣氛很歡樂喔...
↘


底下的新人聚精會神的再聆聽。
↘


交換戒指
↘


掀頭紗
↘


祝福
↘


說完新郎可以吻新娘了,接下來就是這種激情狂吻了...真令人臉紅心跳啊...
↘


詩歌祝福
↘


Rita 給媽媽一個深深的擁抱,媽媽...謝謝您。
↘


入洞房囉...接下來兒童不宜,所以就不貼囉...呵呵...其實接下來我也沒拍到啦!THE END!
↘


不知道大家知不知道 meld 這個 visual diff viewer 呢!?個人覺得在 Linux 的環境底下這可能是最好的 viewer 了。有機會再跟各位詳細介紹吧!

如果沒有安裝過不妨先安裝一下:

sudo apt-get install meld

接著設定 GIT 讓他使用 Meld :
git config --global diff.external meld

然後像往常一樣比較某一個檔案:
git diff HEAD^ filename
其中 HEAD^ 是指上一個版本。

Meld 會被叫起來,但是會說參數錯誤 "Wrong number of arguments (Got 7)"。 原因是 GIT 會送 7 個參數給 Meld ,但是 Meld 只需要兩個參數,兩個需要比較的檔名。所以不能直接用 Meld ,必須要做一點小修改:

在自己的的目錄下建立一個 git-meld.sh 的 script:
vi ~/git-meld.sh

加入以下內容:
#!/bin/sh
meld $2 $5

改變檔案的屬性:
chmod 777 ~/git-meld.sh

然後把 external diff 改成這個 shell script :
git config --global diff.external ~/git-meld.sh

大功告成。

Ubuntu 9.04 之前的 gcc 和 g++ 的版本都是 4.3 的,但是 Ubuntu 9.10 以後卻換成了 4.4 的。 而 4.4 除了檢查更加嚴格外也改了某些函數的回傳型別,把 char* 改成了更嚴謹的 const char* 其用意是讓這些函數更安全。

由於修改 android source code 可是一大工程,而且 source code 隨著 google 的修改版本一直在 update ,除非決定自己 maintain 否則修改可不是一個合理的行為。所以把 gcc 和 g++ 還原成 4.3 版是一個比較可行的辦法。

首先安裝 4.3 版的 gcc 和 g++ :


sudo apt-get install gcc-4.3 g++-4.3 g++-4.3-multilib


接著刪掉原本的 link :


sudo rm /usr/bin/gcc
sudo rm /usr/bin/g++


產生指到成舊版的 link :


sudo ln -s /usr/bin/gcc-4.3 /usr/bin/gcc
sudo ln -s /usr/bin/g++-4.3 /usr/bin/g++


補充:在 Ubuntu 10.10 之後有一種稱為 fastjar 的工具, 是以 c 語言寫成的工具,比原本 java 版本的快了 100 倍. 但是目前有一些穩定性的疑慮,所以如果在 Ubuntu 10.10 發現類似 "unable to access file: corrupted zip file" 這樣的錯誤,可以試著執行:

sudo update-alternatives --config jar


然後會出現:
There are 2 choices for the alternative jar (providing /usr/bin/jar).

Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/fastjar 100 auto mode
1 /usr/bin/fastjar 100 manual mode
2 /usr/lib/jvm/java-6-sun/bin/jar 63 manual mode

Press enter to keep the current choice[*], or type selection number:


輸入 2, 選擇 java 版的就可以了。

自從家裡有個小搗蛋出生之後,對這種防過敏的東西就特別有興趣。因為我本身有過敏的體質,所以很希望這種不好的過敏現象不要發生在下一代身上。關於對抗過敏基本上可以分成兩派,死豬不怕水燙派跟預防派,死豬派是認為基本上環境不是個人小小的力量可以改變的,就算是改變了自家的環境,到了外面依然污染嚴重,既然如此就應該讓小孩從小習慣污染,以後才能適應惡劣的環境。另一派的說法是從過敏發生的原因來著手,過敏的原因其實就是身體對抗污染環境的一種保護機制,也是對抗體對自身發出的一種警告。抗體的本意是好的,他盡忠職守的阻止過敏原進入人體,所以才會一直打噴嚏流鼻水。然而更深入研究會發現,這些抗體其實本來是不認識這些過敏原的,當過敏原與抗體接觸後,抗體才會產生記憶來記住這些過敏原,等下次再發現這些過敏原,抗體就會起來對抗。這也就是為什麼花粉症通常再搬到某個地方的第二年以後才會發生。

基於我是預防派的,所以對486強烈推薦的「大王空氣清淨機」一直有著濃厚的興趣。終於在一次過敏又來襲的時候,敗給了心中的小惡魔..../_\
有興趣的人請看請看486的文章:
http://blog.yam.com/kiss486/article/26499887
http://blog.yam.com/kiss486/article/29637297

廢話不多說,直接開箱吧!


箱子超大的...

打開箱子終於看到廬山真面目了,真的很大一台,甚至快要是除濕機兩倍大了,但是也是這麼大台才稱的上是大王,因為他的濾網也很大。

打開前面的蓋子可以很清楚的看到 HEPA 濾網,這就是可以有效過濾過敏原的關鍵啦!又大又厚呢!家裡的過敏原就靠你來清除了。

喔...幸好有輪子可以在房子裡推來推去,真是貼心的設計。

這次的團購還有附贈10片活性炭濾網以及馬達五年保固,真的很划算,難怪熱銷近600台。

這幾天用下來的結果真的很不錯,機器一啟動,真的可以明顯的感覺到空氣變好了。很神奇的是今天我本來鼻子又不通了,所以給他打開強力風速,咦...開機大概一個小時我的鼻子竟然通了,神奇啊...讚啦!...^^

基本上 Emulator /system 目錄是唯讀的,要解除其唯讀屬性可以透過下列方法:

adb remount
adb push libmy.so /system/lib

但是,在 Android 2.0 (Eclair) 以後,上面的作法會出現這樣的錯誤:
failed to copy 'hosts' to '/system/etc/hosts': No space left on device
或
failed to copy 'hosts' to '/system/etc/hosts': Out of memory

解決方法是,開啟模擬器時不要直接從 AVD Manager介面開,請下指令:
emulator -avd youravdname -partition-size 128
接著再對這個模擬器使用上面的方法就不會出現錯誤了。

深究其原因是 partition size 預設是 64MB。從 adb shell 用 df 指令觀察的結果,/system 在2.x 的 image mount 之後剩下空間是 0K。因此即使 remount 之後也無法寫入。

Filesystem           1k-blocks      Used Available Use% Mounted on
tmpfs                   128276         0    128276   0% /dev
tmpfs                   128276         0    128276   0% /mnt/asec
/dev/block/mtdblock0     77568     77568         0 100% /system
/dev/block/mtdblock1    129152     54988     74164  43% /data
/dev/block/mtdblock2     65536      1156     64380   2% /cache
/dev/block/vold/179:0
                       1044472     65608    978864   6% /mnt/sdcard
/dev/block/vold/179:0
                       1044472     65608    978864   6% /mnt/secure/asec

可惜AVD Manager 沒地方可以設定 partition size。所以目前只能在 console 以手動下指定開emulator囉。

有用過 Android adb shell 的人應該都知道這個 shell 的功能實在是食之無味棄之可惜的雞肋,一些常用的 linux command 幾乎都不支援,所以今天要介紹 busybox 這個工具,它的支援相當豐富,以下是執行的畫面:

$ busybox
BusyBox v1.16.0 (2010-01-27 20:00:00 CET) multi-call binary.
Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko
and others. Licensed under GPLv2.
See source distribution for full notice.

Usage: busybox [function] [arguments]...
   or: function [arguments]...

 BusyBox is a multi-call binary that combines many common Unix
 utilities into a single executable.  Most people will create a
 link to busybox for each function they wish to use and BusyBox
 will act like whatever it was invoked as.

Currently defined functions:
 [, [[, acpid, addgroup, adduser, adjtimex, ar, arp, arping, ash, awk,
 basename, beep, blkid, brctl, bunzip2, bzcat, bzip2, cal, cat, catv,
 chat, chattr, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt,
 cksum, clear, cmp, comm, cp, cpio, crond, crontab, cryptpw, cttyhack,
 cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df,
 dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, du,
 dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid,
 ether-wake, expand, expr, fakeidentd, false, fbset, fbsplash, fdflush,
 fdformat, fdisk, fgrep, find, findfs, flash_eraseall, flash_lock,
 flash_unlock, flashcp, fold, free, freeramdisk, fsck, fsck.minix,
 fsync, ftpd, ftpget, ftpput, fuser, getopt, getty, grep, gunzip, gzip,
 halt, hd, hdparm, head, hexdump, hostid, hostname, httpd, hush,
 hwclock, id, ifconfig, ifdown, ifenslave, ifplugd, ifup, inetd, init,
 inotifyd, insmod, install, ionice, ip, ipaddr, ipcalc, ipcrm, ipcs,
 iplink, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5,
 klogd, last, length, less, linux32, linux64, linuxrc, ln, loadfont,
 loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls,
 lsattr, lsmod, lspci, lsusb, lzmacat, lzop, lzopcat, makedevs,
 makemime, man, md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mke2fs,
 mkfifo, mkfs.ext2, mkfs.minix, mkfs.vfat, mknod, mkpasswd, mkswap,
 mktemp, modprobe, more, mount, mountpoint, msh, mt, mv, nameif, nc,
 netstat, nice, nmeter, nohup, nslookup, ntpd, od, openvt, passwd,
 patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill,
 popmaildir, poweroff, printenv, printf, ps, pscan, pwd, raidautorun,
 rdate, rdev, readahead, readlink, readprofile, realpath, reboot,
 reformime, renice, reset, resize, rm, rmdir, rmmod, route, rpm,
 rpm2cpio, rtcwake, run-parts, runlevel, runsv, runsvdir, rx, script,
 scriptreplay, sed, sendmail, seq, setarch, setconsole, setfont,
 setkeycodes, setlogcons, setsid, setuidgid, sh, sha1sum, sha256sum,
 sha512sum, showkey, slattach, sleep, softlimit, sort, split,
 start-stop-daemon, stat, strings, stty, su, sulogin, sum, sv, svlogd,
 swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar,
 taskset, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time,
 timeout, top, touch, tr, traceroute, traceroute6, true, tty, ttysize,
 tunctl, tune2fs, udhcpc, udhcpd, udpsvd, umount, uname, uncompress,
 unexpand, uniq, unix2dos, unlzma, unlzop, unzip, uptime, usleep,
 uudecode, uuencode, vconfig, vi, vlock, volname, wall, watch, watchdog,
 wc, wget, which, who, whoami, xargs, yes, zcat, zcip

網路上已經有人幫忙把 busybox comile 成 android 可以用的 binary 檔了,有需要的人可以到這裡下載。

安裝 busybox 的步驟如下:

1. 建立安裝的目錄
adb shell mkdir /data/busybox

2. 複製 busybox 的 binary 檔到前一個步驟所建立的目錄:
adb push busybox /data/busybox/busybox

3. 開始安裝 busybox
adb shell
cd /data/busybox
./busybox --install. 
然後你可以檢查 /data/busybox 目錄,裡面應該有許多links.
但是預設的路徑並沒有被指定到 /data/busybox 為了讓用起來方便一點,可以修改 init.rc 多加進去 busybox 的安裝路徑,但如果是在 emulator 上 run 那就要去修改 ramdisk.img 才能達到一勞永逸的效果,否則每次開啟 emulator 後 init.rc 會被覆蓋掉。

修改 ramdisk.img 的步驟:

2.6內核開始,initrd.img採用cpio壓縮,ramdisk.img也一樣,使用gunzip解壓縮,然後再使用 cpio解包。

1. 將 ramdisk.img 從 android sdk 的 platroms\android-xx 目錄下複製到 linux 的作業環境其他目錄(如果已經在 linux 下則此一步驟省略)

2. 名稱改為 ramdisk.img.gz 並用 gunzip 解壓
mv ramdisk.img ramdisk.img.gz
gunzip ramdisk.img.gz

3. 新建一個文件夾 ramdisk 並進入此目錄後用 cpio 解開
mkdir ramdisk
cd ramdisk
cpio -i -F ../ramdisk.img
此時現在目錄已經是解開後的 ramdisk 檔案目錄了

4. 修改 init.rc 在 PATH 中加上 /data/busybox 路徑
## Global environment setup
##
env {
#其中, /data/busybox 為busybox安裝路徑,bash也是放在其中
PATH /data/busybox:/sbin:/system/sbin:/system/bin
...
}

5. 重新打包 ramdisk
find . | cpio -o -H newc -O ../new_ramdisk.img
gzip ../new_ramdisk.img

6. 把 new_ramdisk.img.gz 改成 ramdisk.img 並複製到 emulator 原來放置 ramdisk.img 的目錄覆蓋掉。大功告成...^^

應該很多人都知道 Android Dalvik 的 Maximum Heap Size 一般都是 16M,如果你的程式非常龐大可能這 16M 連跑都跑不起來,這時就要把 Heap Size 放寬才行,那麼該如何放寬限制呢?以下提供幾種方法把 heap size 從 16M 改成 64M:

1. 第一種方法是提供給想在實機上執行程式並且有能力修改 android framework 的朋友,直接到 android source code 目錄,打開 frameworks\base\core\jni\AndroidRuntime.cpp 找到有關建字"16m"這一行,改成"64m":

property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "64m");
重新產生 android image 就大功告成了。

2. 第二種方法是提供給想在 Emulator 上執行程式的朋友,請修改 config.ini 並加入這一行(註1):
vm.heapSize=64

3. 如果上述兩種辦法都不可行,試試看第三種方法,在 /data 目錄下產生 local.prop 並修改檔案內容,加入 dalvik.vm.heapsize=64m ,例如在 shell 模式下輸入:
cd /data
echo dalvik.vm.heapsize=64m > local.prop


註1:
如果在你是 Windows 底下開發的話,這個檔案一般會放在 "C:\Documents and Settings\YourAccount\.android\avd\YourAVD\"

其實 Android 製作 .apk 的 Private Key 是放在 \build\target\product\security 這個目錄下,這裡有好幾組 Key 而其主要的差異如下:

testkey -- a generic key for packages that do not otherwise specify a key.
platform -- a test key for packages that are part of the core platform.
shared -- a test key for things that are shared in the home/contacts process.
media -- a test key for packages that are part of the media/download system.

因此,如果你希望在 Android 建制 Framework 的過程中把你寫的 Application 改成你所指定的 Private Key ,基本上你需要改動的就是 testkey ,這個目錄下還有個 mkkey.sh 來協助你作這樣的工作, mkkey.sh 的內容如下:

if ["$1" == ""]; then
 echo "Create a test certificate key."
 echo "Usage: $0 NAME"
 echo "Will generate NAME.pk8 and NAME.x509.pem"
 echo "  /C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com"
 return
fi

openssl genrsa -3 -out $1.pem 2048

openssl req -new -x509 -key $1.pem -out $1.x509.pem -days 10000 \
    -subj '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

openssl pkcs8 -in $1.pem -topk8 -outform DER -out $1.pk8 -nocrypt

說穿了,就是利用 openssl 來產生新的 Private Key,所以更改的方法很簡單,你可以把 openssl req -new ... 這一行改成你所需要的格式, 接著你只要執行 mkkey.sh 就可以產生新的 Private Key 了! 讚吧!

上一個方法是把 Private Key 跟 Certificate 直接換掉,如果你已經有現成的 Certificate 可以使用,令一個比較簡單的方法是更改 Android.mk 的設定,加一行:


LOCAL_CERTIFICATE := vendor/example/certs/app

如此,在 build system 的時候就可以使用指定的 Certificate 了。

可是這樣還離完美差一點點,你也許想把這個 Private Key 放到 Java 的 .keystore 檔案去,關於這個問題可以參考這篇文章http://www.agentbob.info/agentbob/79-AB.html,裡面有很詳細的說明。

OK, 到這裡為止一切就算是大功告成囉!

<有背景音樂,請打開喇叭,音樂檔很大,請耐心等候>

好久以前曾經寫過同事 Catherine 的婚禮紀錄,後來寫紀錄的網站關了,紀錄也就跟著消失了...嗚...好想哭啊...~>_<~ 現在只好重寫了, 話說美麗的 Catherine 小姐要結婚了,作為同事兼攝影社社長的我能給予最大的祝福,莫過是盡心幫她完成一個美好的婚禮紀錄了,看到她那幸福的模樣讓我也覺得很幸福。

在化妝室的時候幫 Catherine 拍了幾張,看得出來有一點小緊張喔!呵呵...
↘

↘

↘


同事 Phil 的小孩來充當小花童,是個小帥哥呢!
↘


小妹妹也很討喜...真可愛...呵呵...so cute...
↘


新郎新娘進場囉!大家掌聲鼓勵鼓勵...
↘

↘


Catherine 發巧克力給大家,為了捕捉現場的氣氛我衝到人群裡近拍,差一點跌個四腳朝天,終於能體會新聞記者有多辛苦了
↘


切蛋糕儀式...
↘


終於到了大家期待的敬酒儀式,嘿嘿...有仇報仇啦...
↘


「得即高歌失即休,多愁多恨亦悠悠;今朝有酒今朝醉,明日愁來明日愁」...大家一起舉杯祝福這對新人吧!乾啦!ㄏㄡ搭啦!
↘


怎麼可以放過這個千載難逢的機會,讓這對新人來個「愛的親親」...嘻嘻...
↘

↘


哇...這個火辣的熱吻真是太激情了...可以確定這對新人增產報國的戰鬥力應該也不在我之下呢...呵呵...
↘


透過酒杯人的表情變得很有趣,有哈哈鏡的效果...^^
↘


這張也是,呵呵...只不過苦主變成新娘了...
↘


新娘的飾品很美麗,我特地拍了幾張...
↘


送客囉!呷甜甜生豪生...
↘


終於結束了,有一個傳說是:「人一生下來就只有一半,於是每個人窮其一生都在找尋那失落的另一半」。如今你找到了妳的另一半,完美了他也完美了妳。看到你們幸福的模樣真替妳感到高興,恭喜ㄋㄟ!一定要永遠幸福下去喔!
↘