儲存空間即將不足

都上 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 嗎? 待驗證。

語言治療(5)

轉眼就第五次上課了,這次上課前發生了請假風波。因為趕著出門,大公子以為是要去學校,所以就情緒激動地叫不要,於是我打電話給醫院老師,跟她請假。結果下了樓,大公子才又說是要去醫院,這下尷尬了,我趕上樓,再打一次電話給老師,說今天還是會去。
今天是爸爸載大公子、媽、二公子跟我一起去的,爸跟媽要去耕莘醫院買醫療用品,二公子就順便一起去,而大公子跟我則到慈濟醫院。到了醫院,大公子喊說餓了,也是該餓的時候了,在家時叫他吃早餐,他死活都不要。就帶他到樓下全家買了蛋酥麵包跟養樂多給他吃,他很快就吃掉半個蛋酥麵包,然後喝完養樂多。
這次上課一開始,老師先問他為什麼心情不好,因為我是以他心情不好的理由跟老師請假的。他沒說,老師就先拿出3個拼圖給他拼,邊拼圖的時候,邊請他講拼圖內的圖案,然後藉機會也問他說,綠色的水果有哪些,橘色的水果有哪些。綠色的水果他只講了芭樂,老師提醒他還有哈密瓜,可惜我們家真的很少吃哈密瓜,西瓜還比較常吃,橘色的水果只講了橘子。
接著拿出三張左右對照的圖片,就左邊是不好的行為,右邊是好的行為,然後教他講跟請他講,有些部份,大公子已經講的不錯了。講到後面時,老師請他跟她講一樣的,大公子總是接著老師的話說,例如:老師說,”好寶寶要”,大公子就直接接話,而不是跟著念”好寶寶要”。老師花了一點時間,才讓他明白要跟著念。等講完這三張圖片,又再拼了3個拼圖。最後老師再請他說為什麼心情不好,大公子才說,”早上不來老師這裡啊”,所以才生氣,老師因此多給了他一張貼紙。
這次講完,老師有跟我說,大公子從評估到現在進步很多,也比一般需要語言治療的孩子要來的好,像是ㄉㄨㄟ,大公子隔週還會記得,一般的孩子則是會忘記。我是說,可能因為從年初到現在,大公子好像正處在爆發期,所以感覺上很快,也跟評估時的情況不一樣。然後有提到回家跟他複習時,他會說”不要說”。老師說,接著會調整課程內容,只是她下週請假一週。
附帶一提,晚上在看綠15路線圖時 (大公子很愛看地圖、路線圖),我發現他已經有在認字了,像”七張”,他就已經可以直接看著念出來,不需要問我。

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為優先… (好吧,我承認我沒認真去看懂程式邏輯,所以說”應該”…)

語言治療(4)

這次一開始,老師就拿了上次”雨傘”故事的圖卡,一張張的內容再帶過一次,然後請大公子來排出順序,邊排邊說。等到故事圖卡排列完,接著拿出一本大書,裏面有許多小小的方形磁鐵,上面貼著各種東西,像是葡萄、獅子、長頸鹿、外套…等等,總共5個大類。由於時間的關係,這次只做3個大類:水果、動物、衣服。老師一樣先帶過一次,確定大公子都知道了,然後把這些小方形磁鐵弄亂,請大公子分類。
在整個過程裡,除了教導大公子講故事以外,也針對大公子某些字的發音跟慣用詞做矯正,例如:”葡萄”的”葡”、”對”、”甜”、”嘟嘟”應該是”火車”…等等。
最後老師說他7/19要請假,那天就暫停一次。
從去醫院評估之後到現在,已經快四個月了,我個人是覺得大公子在這段期間進步很多,希望在年底前就可以不用再去上語言治療課程。

語言治療(3)

第三次上課。基本上每次上課就只有半個小時,但為了這半小時,不管是大人、小孩都需要請半天假。第一次上課時,是大人請半天,大公子請整天,第二次之後,就是都請半天了。
這周是把上週的故事「雨傘」講完,除了講後半本的部份,也讓大公子重頭再講一次。邊講故事邊糾正大公子的某些發音,例如:「對」,大公子常念成「貴」,老師教他先念「ㄉㄨ」,再念「ㄟ」,合起來就是「ㄉㄨㄟˋ」。最後和大公子玩記憶卡片的遊戲 ,把兩兩一張的卡片共五組,洗牌後蓋起來,一人一次翻兩張牌,翻到一樣的牌就拿起來,算得分一次;翻到不一樣的牌就要再蓋回去,看誰拿到的牌組多。

語言治療(2)

第二次上課。這次上課跟上次頗類似,但改用故事書「雨傘」,由於時間因素只講了半本。同樣的,在小朋友感到不耐煩時,有拿出拼圖之類的,讓小朋友先短暫的移開注意力,讓他喘息一下,一方面也是作為激勵因子。

語言治療(1)

第一次上課。
老師先拿出一個可以分拆成六片的六格連環圖畫,然後拆開。從第一張圖片去誘導小朋友說出裏面有什麼東西,並且做了什麼,如果說不出來,就說一遍,再請小朋友說一遍;小朋友厭煩了,就說看完三張,可以吹泡泡。最後六張都看完、說完了,就請小朋友從頭講一次。
吹泡泡時也有技巧,老師會注意小朋友嘴型;大公子是牙齒咬住去吹,所以都不容易吹出大泡泡。老師會特別請他牙齒不要咬住去吹,這樣吹出大泡泡的機率就提高了。

根據changelog取版號

以前上傳ppa之前,都是手動打指令,其實應該要自動化才對,今天跨出第一步。第一步當然就是取版號,deb的版號是從debian/changelog來的,所以要從這裡著手。

當前的版號只會在第1行,一開始就想到用 head -n 1來取,用 awk 印出第2欄。可是第2欄前後有 () 呢?該怎麼拿掉呢?不會是要用 sed 吧? 去 GNU awk manual 翻閱了一會,發現有 match 函數,可以用 re 來取 group,所以用 match($2, /\((.*)\)/,arr); 就可以去掉 ()。

去掉 () 之後,想到應該可以把 head 省掉,也用 awk 處理。NR 是一個特殊的變數,當處理一筆(行)時,這個值就會累加。把它限定為 1,就表示只處理第1行了。於是就可以湊出這麼一段script。

CHANGE=`awk 'NR==1 {match($2, /\((.*)\)/,arr);printf("gcin_%s_source.changes", arr[1]);}' debian/changelog`
ls -l $CHANGE

distutils bdist_rpm

CentOS 5.6 裡的MySQL-python是1.2.1,在用django的時候,它給我吐出需要MySQL-python-1.2.1p2 以後的版本才行。
囧掉,這樣不就要抓MySQL-python新版來包,好像會很麻煩說。上MySQL-python官網去看,發現維護者很有意思,他在Amazon上的wish list裡都是大力水手的DVD,如果要贊助他的話,不妨幫他買DVD,Amazon會送到他家裡去。離題了,網站上最新的版本是1.2.3,就先抓下來吧。
python的moodule照慣例都有 setup.py,就想說打 python setup.py –help-commands 來看看,結果喜出望外,裏面有 bdist_rpm 的指令,這表示我可以直接打 python setup.py bdist_rpm 就可以建出 rpm 了。
於是馬上就來 build,首先裝上 mysql-devel,然後執行 python setup.py bdist_rpm,看起來很順利,但最後卻發現沒有 MANIFEST 檔案,而導致失敗。看了一下檔案,發現有 MANIFEST.in,再看一下裏面,沒有什麼要替換的字串 (一般來說,副檔名是 .in 的,都會需要用 sed 來替換一些字串),就直接 cp MANIFEST.in MANIFEST 補上,再重新執行 python setup.py bdist_rpm 就大功告成了。rpm 會放在 dist 目錄下,收工。

cpio的pass through

以前沒想過 cpio 的 pass through 可以做什麼,今天要不是有朋友問我,我大概也不會想到這個。是這樣子的,假定有個目錄 a,裏面有很多目錄跟檔案,可是只要複製 a/b/c/file.txt 跟 a/b/file2.txt 到目錄 t 下,可是沒辦法用 cp -r,因為 cp -r 會把整個 a 都複製過去,總不能先複製過去以後再一個一個刪除吧? 本想說這可能要寫 script 來做了,打了 cp,按了 tab,看有沒有什麼可能的指令可用,就看到 cpio,印象中,cpio 可能是可以。

最初的想法是用兩個 cpio 來做,一個建 archive(cpio -o),一個解到指定的目錄(cpio -i),這樣就行了。用 info cpio 一查,發現 cpio -p 應該就可以做了。

所以試了一下,這裡先建立一個 list 檔案,裏面有兩行:a/b/c/file.txt 跟 a/b/file2.txt,a 目錄下有很多目錄跟檔案,並且有 a/b/c/file.txt 跟 a/b/file2.txt。那麼這兩行指令就可以只把list裡指定的兩個檔案複製到 t 目錄下,並且建立必要的目錄:

mkdir -p t
cat list | cpio -p --make-directories t