前陣子收到一隻手機,需要把 Firefox OS porting 上去。剛好之前有看過這幾篇文章 B2G Porting, 三步驟 build 好 Firefox OS及透過 AOSP build system 來 build Firefox OS,不然還真不知道從那裡開始。先費了一翻功夫把 manifest 弄出來,再經過一陣苦戰之後 system.img 總算也編出來了。既然 system.img 都出來了,當然要鼓起勇氣把它 flash 到手機裡看看。其實早就有心理準備,怎麼可能一次就成功呢?只是還不知道會碰到什麼樣的問題。果然 flash 進手機後,開機畫面一片黑,發生了什麼事了呢?
先用 adb shell 進去看看,結果發現 Firefox OS 主程式根本就沒有在執行。試著用手動去執行看看也失敗,錯誤信息是 Permission Denied。有使用 linux 經驗的朋友,這時應該都會做這件事情,檢查看看相關執檔的屬性。結果發現執行檔的屬性都是 0644。
$ adb shell ls -l /system/b2g/
-rw-r--r-- root root 116116 2014-03-13 03:09 b2g
-rw-r--r-- root root 5296 2014-03-12 02:22 plugin-container
-rw-r--r-- root root 82380 2014-03-12 02:22 updater
1234
$ adb shell ls -l /system/b2g/-rw-r--r-- root root 116116 2014-03-13 03:09 b2g-rw-r--r-- root root 5296 2014-03-12 02:22 plugin-container-rw-r--r-- root root 82380 2014-03-12 02:22 updater
暫時先不管為什麼會變成 0644,把 /system 重新 mount 成 rw,把執行檔全部改成 0755,再手動執行一次,真的有畫面跑出來了。
雖然重新開機後也可以跑起來了,但每次 flash system.img 後,檔案屬性就會跑掉,那還真不方便。這時我突然想到曾經看到過一個 patch, 但在每次開機時 init.rc 都需要去修改檔案屬性好像也不是一個好方法。那就來弄清楚問題出在那裡吧!
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -98,6 +98,9 @@ on fs
# Mount /system rw first to give the filesystem a chance to save a checkpoint
mount yaffs2 mtd@system /system
+ chmod 0755 /system/b2g/b2g
+ chmod 0755 /system/b2g/plugin-container
+ chmod 0755 /system/b2g/updater
mount yaffs2 mtd@system /system ro remount
123456789
--- a/rootdir/init.rc+++ b/rootdir/init.rc@@ -98,6 +98,9 @@ on fs # Mount /system rw first to give the filesystem a chance to save a checkpoint mount yaffs2 mtd@system /system+ chmod 0755 /system/b2g/b2g+ chmod 0755 /system/b2g/plugin-container+ chmod 0755 /system/b2g/updater mount yaffs2 mtd@system /system ro remount
首先來檢查看看編出來的檔案,發現編出來的執行檔屬性都是正確的。
$ ls -l system/b2g/
-rwxr-xr-x root root 116116 2014-03-13 03:09 b2g
-rwxr-xr-x root root 5296 2014-03-12 02:22 plugin-container
-rwxr-xr-x root root 82380 2014-03-12 02:22 updater
1234
$ ls -l system/b2g/-rwxr-xr-x root root 116116 2014-03-13 03:09 b2g-rwxr-xr-x root root 5296 2014-03-12 02:22 plugin-container-rwxr-xr-x root root 82380 2014-03-12 02:22 updater
那為什包成 system.img 燒進手機後屬性就變了呢?
在編 system.img 時,相關 build tools 在把一個資料夾包到一個 .img 檔時,可以對檔案的屬性進行調整。我有把 Firefox OS 相關執行檔的屬性對照都有新增到 android_files[]。
在 android_filesystem_config.h 有一個 function fs_config 會使用到 android_files[]。任何 tools 只要來 include 這個 header file 就可以使用這個 function 來調整相關檔案的屬性。
/ system/core/include/private/android_filesystem_config.h /
static const struct fs_path_config android_files[] = {
{ 00755, AID_ROOT, AID_ROOT, 0, "system/b2g/b2g" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/b2g/updater" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/b2g/plugin-container" },
...
}
...
static inline void fs_config(const char path, int dir,
unsigned uid, unsigned gid, unsigned mode, uint64_t capabilities)
{
const struct fs_path_config pc;
int plen;
if (path[0] == '/') {
path++;
}
pc = dir ? android_dirs : android_files;
plen = strlen(path);
for(; pc->prefix; pc++){
int len = strlen(pc->prefix);
if (dir) {
if(plen < len) continue;
if(!strncmp(pc->prefix, path, len)) break;
continue;
}
/ If name ends in then allow partial matches. /
if (pc->prefix[len -1] == '') {
if(!strncmp(pc->prefix, path, len - 1)) break;
} else if (plen == len){
if(!strncmp(pc->prefix, path, len)) break;
}
}
uid = pc->uid;
gid = pc->gid;
mode = (mode & (~07777)) | pc->mode;
*capabilities = pc->capabilities;
}
123456789101112131415161718192021222324252627282930313233343536373839404142
/ system/core/include/private/android_filesystem_config.h / static const struct fs_path_config android_files[] = { { 00755, AID_ROOT, AID_ROOT, 0, "system/b2g/b2g" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/b2g/updater" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/b2g/plugin-container" },...} ... static inline void fs_config(const char path, int dir, unsigned uid, unsigned gid, unsigned mode, uint64_t capabilities){ const struct fs_path_config pc; int plen; if (path[0] == '/') { path++; } pc = dir ? android_dirs : android_files; plen = strlen(path); for(; pc->prefix; pc++){ int len = strlen(pc->prefix); if (dir) { if(plen < len) continue; if(!strncmp(pc->prefix, path, len)) break; continue; } / If name ends in then allow partial matches. / if (pc->prefix[len -1] == '') { if(!strncmp(pc->prefix, path, len - 1)) break; } else if (plen == len){ if(!strncmp(pc->prefix, path, len)) break; } } uid = pc->uid; gid = pc->gid; mode = (mode & (~07777)) | pc->mode; *capabilities = pc->capabilities;}
有那些 tools 會呼叫到 fs_config 呢?
使用 ext4fs 檔案系統時會用的 make_ext4fs 有來 include android_filesystem_config.h,也有呼叫到 fs_config。
/ system/extras/ext4_utils/make_ext4fs.c /
fs_config_func = fs_config;
...
if (fs_config_func != NULL) {
int dir = S_ISDIR(stat.st_mode);
fs_config_func(dentries[i].path, dir, &uid, &gid, &mode, &capabilities);
dentries[i].mode = mode;
dentries[i].uid = uid;
dentries[i].gid = gid;
dentries[i].capabilities = capabilities;
}
123456789101112
/ system/extras/ext4_utils/make_ext4fs.c / fs_config_func = fs_config;... if (fs_config_func != NULL) { int dir = S_ISDIR(stat.st_mode); fs_config_func(dentries[i].path, dir, &uid, &gid, &mode, &capabilities); dentries[i].mode = mode; dentries[i].uid = uid; dentries[i].gid = gid; dentries[i].capabilities = capabilities; }
在 yaffs2 檔案系統會使用到的 mkyaffs2image,也有 include android_filesystem_config.h 及呼叫 fs_config。
/ yaffs2/utils/mkyaffs2image.c /
static void fix_stat(const char path, struct stat s)
{
uint64_t capabilities;
path += source_path_len;
fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities);
}
12345678
/ yaffs2/utils/mkyaffs2image.c / static void fix_stat(const char path, struct stat s){ uint64_t capabilities; path += source_path_len; fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities);}
這也太巧合了吧,我 porting 的這隻手機使用的是 ubifs,都沒有使用前面提到的這兩個 tools。相較於 yaffs2,ubifs 支持壓縮及還有一些其他優點,通常在 nand flash 容量較少的手機上就有可能使會用 ubifs。當然 ubifs 也不是完全沒有缺點,如果想要了解 nand flash 上不同檔案系統的特性可以參考這份 測試報告。
回到正題,這隻手機上的 ubifs 真的出了什麼問題嗎?檢查後發現 ubifs 使用的 mkfs.ubifs 沒有 include android_filesystem_config.h 當然也不會呼叫到 fs_config!
看來問題就出在這裡,就來試試看吧。先到 ubifs_utils/mkfs.ubifs/mkfs.ubifs.c 裡新增 fix_stat,然後在 add_directory 及 write_data 這兩個 function 裡來使用 fix_stat。重編 mkfs.ubifs 後,再把 system.img 編出來,flash 到手機一試,結果一切正常,看來這才是正解。
/ system/extras/ubifs_utils/mkfs.jffs2.c /
static void fix_stat(const char path, struct stat s)
{
uint64_t capabilities;
path += source_path_len;
fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode,&capabilities);
}
static int write_data(void)
{
...
if (fixstats)
fix_stat(root, &root_st);
...
}
static int add_directory(const char dir_name, ino_t dir_inum, struct stat st,
int non_existing)
{
...
if (fixstats)
fix_stat(root, &root_st);
...
}
123456789101112131415161718192021222324
/ system/extras/ubifs_utils/mkfs.jffs2.c / static void fix_stat(const char path, struct stat s){ uint64_t capabilities; path += source_path_len; fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode,&capabilities);} static int write_data(void){... if (fixstats) fix_stat(root, &root_st);...}static int add_directory(const char dir_name, ino_t dir_inum, struct stat st, int non_existing){... if (fixstats) fix_stat(root, &root_st);...}
