網路上可以找到很多文章,不過大多都是講怎麼用,而沒有提到原理,所以就想找找看。
最初找到的是這篇:Android adb setuid提权漏洞的分析,裡面就寫得很清楚了,他寫的不是 z4root,而是 RageAgainstTheCage,主要是靠著一直建 process,建到極限值,然後試著砍掉 adb,再靠 adb 程式沒有檢查 setuid 傳回值的漏洞來取得 root 權限。一般的 daemon 程式都是這樣子,一開始是 root,之後會用 setuid 切換身份,所以在 setuid 之前都是 root。而 setuid 通常不會失敗,但是因為可用的程序限制到了,才失敗 (參考 kernel/sys.c 裡的 set_user)。
好,那跟 z4root 又有什麼關係?還好 z4root 有源碼。
z4root 裡就有用到 RageAgainstTheCage,z4root.java 是主要的 Activity,當你 click root 按鈕值,會啟動 Phase1 Activity,這邊就會把包成 resource 的 RageAgainstTheCage 寫到z4root的應用程式目錄下,然後變更其權限並且執行。噹噹,執行完以後,當然 adb 就有 root 權限了。
然後 Phase1 有 thread 去持續檢查執行 RageAgainstTheCage 的程序,如果成功了,會利用 Alarm 服務去啟動 Phase2。Phase2 這邊我有點不太明白,最後是將 su、busybox、SuperUser.apk 都搬到系統分割區了,然後就重開機,可是這個時候怎麼會有權限可以作這些事情呢? 如果照上面的 RageAgainstTheCage 來看,我猜想應該是在執行 RageAgainstTheCage 時,把程序數衝到最大限制,然後之後所執行的程序其實都是 root 啟動的,要切換使用者身份時失敗,所以之後的程序都是 root,也因此 Phase2 Activity 也有同等的 root 權限。這邊因為跟 java 的 thread 作法不是很熟,所以就不了了之。
z4root 最後是重開機,此時已經有埋必要的 su 跟 SuperUser.apk 在系統裡,也就有了可以 root 的可能。
在Android直接以zxing去解碼圖檔
zxing的Android client 端,是直接不斷的進行自動對焦的動作,然後接 Camera 的 Preview,這時候接出來的影像是 YUV 格式的,然後就直接去做判讀。所以,我當下的想法是在這邊直接去讀取一個 YUV 格式的影像檔,讀完就給 zxing decoder 去判讀,但是失敗。我認為可能是我轉換出來的 YUV 有問題。我是這樣轉換的,先用 ImageMagick 的 convert 把 png 轉成 ppm,再用 ppmtoyuv 轉成 yuv。
後來去看了 zxing 的 JavaSE client,他是用 awt 去做影像轉換,就想,可以把 awt 移植到 Android 去嗎? 上網找了一下,還真的有人做,只是後來專案就沒再開發了。
最後還是 stackoverflow 的幫忙:android – Embed Zxing library without using Barcode Scanner app,原來 zxing 裡的 Android client 測試程式裡就已經有一個 import com.google.zxing.client.androidtest.RGBLuminanceSource 可以處理這件事情,所以就先用 BitmapFactory.decodeFile 把圖檔讀出,得到 Bitmap,再把 Bitmap 丟給 RGBLuminanceSource 裡,就可以再用 new BinaryBitmap(new HybridBinarizer(source)); 得到 BinaryBitmap,decode 就可以根據這個 BinaryBitmap 取到條碼了。詳細的程式可以參考Stack Overflow 文裡的程式碼。,這裡不再摘錄。
link2sd
link2sd 是一個可以把應用程式從內部記憶體移到 SD Card 上的應用程式,你需要把 SD Card 切成兩個主要分割區(primary partition),第一個分割區作為正常的 SD Card 使用,第二個分割區就拿來存放應用程式。
之前用的時候,我是將第二個分割區格式化為 vfat,但用了一段時間以後,覺得效率不是很好,也為了 journaling filesystem,就想把 vfat 換為 ext3。研究了好一陣子,昨天決定下手了。
首先先說明我對 link2sd 的了解,照理說,一般要額外掛載分割區是需要額外寫 script 的,link2sd 是寫在 /system/etc/install-recovery.sh 裏面。所以我就簡單修改這個 script,然後關機把 SD Card 拿出來將第二個分割區備份,再格式化為 ext3,再把備份出來的檔案回存回去。但很遺憾,不行。
於是我去看 init.rc,裏面沒有啟動 /system/etc/install-recovery.sh 這一段,我知道編譯 android 源碼以後得出來的 init.rc 是有這段的。於是我修改 init.rc,加入這段,可是重開機以後,再去看 init.rc,我加的這段居然消失了。
沒辦法,只好還原回 vfat,乖乖的使用。
Android上的電子書
昨天想起介紹 Kobo eBooks 的那篇文章說 Kobo eBooks 可以吃 epub 格式的電子書,可是一直都忘記試,今天早上上班時,就試了一下,發現閱讀的效果真的比 FBReader 好很多。fbreader用來對付一般的小說是綽綽有餘,但遇到有程式碼的epub,整個就爛給你看,而且是爛的可怕。Kobo eBooks 的處理就好很多,網站上有提供免費電子書可下載,也有像類似 foursquare 的打怪機制,讓你讀書跟打怪一樣,讀的愈多,拿的勳章愈多。
拿 Kobo eBooks 跟 Kindle 比的話,在記憶體少的機器上運行ok。每次開 Kindle,就常讓我的Asus A50重開機,重開機之後再去開啟程式才能正常進入,常常讓我不知道該不該賭一下,我想這應該是Linux Kernel 發現記憶體不足而砍應用程式的關係。
要說 Kobo eBooks 缺點的話,大概就是沒辦法查字典,Kindle是可以查的。Kindle 在長按單字時,他會自動去查英英字典,第一次查的時候,程式會告訴你要額外送你一本英英字典,下載以後,就可以有自動查單字的功能,畫面是以 pop window 的方式呈現,再點選,會進到英英字典,顯示更多資訊。
如果沒意外的話,我想我以後都會拿 Kobo eBooks 來讀 epub。
除了上面的3個電子書以外,我還有試過 iReader,是同事推薦我的,Market 裡的評價不錯,但iReader網站上的書太多,一時不知道要下載什麼,大多都是簡體中文,又考慮到翻譯品質良莠不齊,所以乾脆就移除掉了。
我還有額外下載獨立電子書的 app:明朝的那些事儿-全集跟黄河鬼棺-全集,這兩個也不錯,作者是同一個,作者有在積極改版,可是我覺得最早用的那版還不錯用,不太需要改。目前明朝的那些事儿-全集還沒看完,才看到第五集,等看完才會看黄河鬼棺-全集。這兩本雖說是免費,但實際上應該算是盜版吧~
儲存空間即將不足(續)
- 想用 statfs 去看 /data 到底是剩多少可用,結果要自己弄 jni,一整個懶惰,就…
- SL4A的python應該可以用吧,查了 python 文件,得知要用 os.statvfs,但是 SL4A 的 os.statvfs 被閹割掉… 囧
- 查 threshold,這個應該是可以的,只是要把 Settings.Secure.SYS_STORAGE_THRESHOLD_PERCENTAGE 改成 “sys_storage_threshold_percentage”,這個沒真的下去寫程式驗證。
- 用 terminal+busybox df 去查 /data 的,total bytes 是 162529280,心一橫,就拿這數字設到 debug.freemem (sudo setprop debug.freemem 162529280),真的,那個討厭的”儲存空間即將不足”的通知就消失了。
以上。但是要裝比較大的app的時候,還是沒辦法裝,可惡!!
儲存空間即將不足
都上 SD Card,加裝 Link2SD 了,才裝幾個程式,Android 手機就開始唉唉叫,左上角老是出現”儲存空間即將不足”的訊息,真的是太令人生氣。本來不想挖程式出來看的,唉~
Android 程式的文字多半是存在 xml 檔案,也就是 resource 檔,關鍵是在於對應所使用的變數名稱。在 mydroid 目錄下先用 source build/envsetup.sh ,再用 resgrep ‘儲存空間即將不足’ 來找,出現這段文字的檔案有兩個,不過很明顯,變數名稱應該是 low_internal_storage_view_title。
再用 jgrep 去找:jgrep low_internal_storage_view_title ,排除掉 R.java 之後,可以看到一個不一樣的:frameworks/base/services/ajva/com/android/server/DeviceStorageMonitorService.java
看來關鍵就在這檔案裡了。從裏面可以看到在 sendNotification 裡,會把 low_internal_storage_view_title 當作訊息丟出去,於是上方的通知欄就有了’儲存空間即將不足的訊息’。那麼是在那邊去 sendNotification 的呢? 是同個檔案裡的 checkMemory()。
checkMemory() 裡的檢查邏輯很簡單,先 getMemThreshold(),再用 mFreeMem 去做判斷,如果比取到的 threshold 值要小,mLowMemFlag 還沒設為true,就先試著清理 cache,再不行,就 sendNotification。
getMemThreshold() 是怎麼取 threshold 的呢?是從 Content Resolver 裡找 “sys_storage_threshold_percentage” 來的,如果沒取到,則以 10 為預設值,然後乘上 mTotalMemory。
好,上面有幾個關鍵的變數:mTotalMemory、mFreeMem,這兩個變數又是怎麼來的?checkMemory() 裡在檢查 mFreeMem 之前,有先呼叫 restatDataDir(),這個函數會呼叫到底層的 C 函數 – statfs 來取得 /data 的資訊,statfs 回傳一個結構體,主要會使用到裏面的 f_bavail、f_bsize、f_blocks。mFreeMem = f_bavail * f_bsize; mTotalMemory = f_blocks * f_bsize。
從上面的資訊看來,如果要避免不足的問題,要不就是增加 /data 的可用空間,要不就是降低 threshold 的值。但原始碼裡透露了另外一個密技,restatDataDir() 裡,在使用 statfs 取得資訊以後,接著去取 System properties 裡的 debug.freemem,如果有取到,就拿這個當作 mFreeMem 的值來用。看來是可以利用的喔~搭配 setprop 可以設置 debug.freemem ,不過需要 root 嗎? 待驗證。
WIFI優先於3G?
蠻怕浪費錢的,所以還去挖code驗證了一下。NetworkStateTracker 用 NetworkUtils.setDefaultRoute() 設置routing。
在ConnectiveService裡有定義優先權,但這邊的陣列值其實是在 framework/base/core/res/res/values/config.xml 中的 networkAttributes:
Type | radio | priority | |
---|---|---|---|
wifi | 1 | 1 | 1 |
mobile | 0 | 0 | 0 |
mobile_mms | 2 | 0 | 2 |
mobile_supl | 3 | 0 | 2 |
mobile_hipri | 5 | 0 | 3 |
所以再依照程式裡的邏輯,應該是WIFI為優先… (好吧,我承認我沒認真去看懂程式邏輯,所以說”應該”…)
make recoveryimage後什麼事都沒有發生
make recoveryimage無法建出recovery image,追蹤build/core/Makefile以後,就可以發現,如果有定義TARGET_NO_KERNEL、TARGET_NO_RECOVERY或BUILD_TINY_ANDROID任一個為true的話,就不會建出來。
而我拿到的SDK的BoardConfig.mk裡,正好就有這麼一行:TARGET_NO_KERNEL:=true
DDMS抓圖
會看這個,是因為抓圖失敗…
ddms 會開啟本地的port 5037,這是由host端的adbd所listen的。接著寫入”framebuffer:” (AdbHelper.getFrameBuffer)。
target端的adbd收到以後,會建立一個thread,thread跑的是framebuffer_service.c裡的code。裏面很簡單,就開啟/dev/graphics/fb0,然後取 fb_var_screeninfo 的值,再根據得到的值來決定要讀多少bytes,寫回去到host端,最後寫完就關閉。
為什麼會抓不到圖呢?不知道,還找不到原因。
vold小記
- 根據 /system/etc/vold.fstab 去monitor可移除裝置。dev_mount label 掛載點 auto或第n個partition /sys下的路徑,要扣掉/sys
- NetlinkManager以netlink和kernel建立溝通管道以取得裝置insert/remove事件並做處置(NetlinkHandler)。
- NetlinkHandler內實際上是呼叫VolumeManager做進一步處理
- VolumeManager
- 管理的是Volume,DirectVolume是其子類別,這裡用了template pattern
- 負責mount/umount/share/unshare/format以及secure container
- 以CommandListener去listen以接收指令,也就是跟上層溝通的管道。(CommandListener, VoldCommand, Process, ResponseCode)。
- Volume/DirectVolume::mountVol 看來是個適合填 android usb gadget 所需資訊的地方。因為
- 有檢查狀態
- 可知道是哪一個partition或disk
- 可得知insert/remove狀態
- 需要/dev/device-mapper,所以kernel要把此部份打勾。這邊的設定還蠻多的:
CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_AUTHENC=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_TWOFISH_COMMON=y
參考資料: