統計手機的簡訊資料

實聯制在4月27日走入歷史,與很多邊緣人一樣, 疫情期間,實聯制佔據了我手機中幾乎所有簡訊的份額。 不誇張地說,或許 1922 將會是我們此生中發過最多簡訊的號碼了!

在和它道別的同時,我也想知道疫情期間自己到底發送了多少簡訊? 那麼,是時候用 adb 這項工具來做點事了!

Android 的簡訊政策

Android 中,每個可見的功能都由特定的 APP 所提供。 在查詢 Android Developer 手冊後, 可以知道所有簡訊 APP 均實作名為 Telephony provider 的 Content Provider , 因此可在名稱為 com.android.providers.telephony 的 APP 中找到手機簡訊的資料。

首先是第一步,備份 com.android.providers.telephony 的所有資料:

adb backup -apk com.android.providers.telephony -f telephony.ab

還原簡訊資料

這個備份出來的 .ab (Android Backup) 檔案嘛,雖然說是 Android 的備份用檔案, 不過平常它需要搭配 adb restore 等指令以還原在 Android 系統上。 就我所知在任何官方文件上都沒有提到其它處理方法。 不過既然我們要讀取它的內容,當然要直接暴力解開啦!

好在根據一些論壇大神的指引,這邊我了解到:.ab 實際上是個用 zlib 作成的 tar 壓縮檔。 另外一個重點是: 該壓縮檔還在開頭加了 24 byte 的前綴,用以標示自己是 Android 的備份檔案。

有了以上的資訊事情就好辦了,這邊直接使用一些基本的指令就可以還原資料:

# 用 tail 印出 24 byte 以後的檔案內容
# 交由 pigz 解壓縮 和 tar 解開
tail -c +25 telephony.ab | pigz -d | tar -xf -

處理原始資料

取得 APP 的原始資料後,接著就簡單了! 目錄下所有結尾為 sms_backup 的檔案都是簡訊資料, 把它們解壓縮即可得到像這樣的 JSON 物件:

{
    "address": "0911510196",
    "body": "親愛的客戶您好:謝謝您使用郵政VISA金融卡於05/26 09:35 消費新臺幣290元,如有疑義,請撥打卡片背面客服電話.",
    "date": "1653528972961",
    "date_sent": "1653528971000",
    "status": "-1",
    "type": "1",
    "recipients": [ "0911510196" ],
    "read": "1"
}
可以見到,除了來源的電話號碼外,也有時間欄位。 有了這些資訊,就可以用 JSON 工具輕鬆處理資料啦! 這邊使用 jq 進行處理。

# 從所有名為 XXXsms_backup 的檔案中
# 取得收件者為 1922 的簡訊資料
# 每筆一行,存檔在 1922.sms
for sms in **/*sms_backup; do pigz -d <$sms; done | \
jq -c '.[]|select(.address=="1922")' >1922.sms
    
# Count how many SMS messages with address = 1922
wc -l 1922.sms

# Get the first and the last time of SMS messages
jq -r .date 1922.sms | sort | sed -n 's/...$//;1p;$p' | xargs -i date -d @{}
因為我上一支手機壞掉時沒有妥善轉移資料,所以最早有紀錄的簡訊是從去年開始。

從以上的指令可以知道:去年10月開始到昨天,4月27日,我總共發了1066則簡訊給 1922 !