使用不同的檔案系統,B2G主程式沒跑起來!

作者:
瀏覽:315

前陣子收到一隻手機,需要把 Firefox OS porting 上去。剛好之前有看過這幾篇文章 B2G Porting, 三步驟 build 好 Firefox OS透過 AOSP build system 來 build Firefox OS,不然還真不知道從那裡開始。先費了一翻功夫把 manifest 弄出來,再經過一陣苦戰之後 system.img 總算也編出來了。既然 system.img 都出來了,當然要鼓起勇氣把它 flash 到手機裡看看。其實早就有心理準備,怎麼可能一次就成功呢?只是還不知道會碰到什麼樣的問題。果然 flash 進手機後,開機畫面一片黑,發生了什麼事了呢?

先用 adb shell 進去看看,結果發現 b2g 主程式根本就沒有在執行。試著用手動去執行看看也失敗,錯誤信息是 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

暫時先不管為什麼會變成 0644,把 /system 重新 mount 成 rw,把執行檔全部改成 0755,再手動執行一次,真的有畫面跑出來了。
使用不同的檔案系統,B2G主程式沒跑起來!

雖然重新開機後也可以跑起來了,但每次 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

首先來檢查看看編出來的檔案,發現編出來的執行檔屬性都是正確的。

$ 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 檔時,可以對檔案的屬性進行調整。我有把 b2g 相關執行檔的屬性對照都有新增到 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;
}

有那些 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;
    }

在 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);
}

這也太巧合了吧,我 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);
...
}