FireFox OS (B2G) 菜鳥看 code

作者:
瀏覽:235

過去的工作一直都是跟 broadband network 相關,整天看的都是網路封包 (network package),檢查封包從 network device 收進來的 formate 對不對? 封包被改得對不對? Network package 走的路徑對不對? Forwarding 的效率夠不夠好? 封包有沒有掉了(掉包了!!!) ? 掉到哪裡去了? 很少有機會去看比較上層接近 user interface (userspace) 相關的東西有的話大概也是跟網路管理有關的部分。

轉過來做 Firefox OS,似乎是轉很大跟之前的領域完全很不一樣就好像是剛畢業的菜鳥到處找資料想瞭解什麼是 Firefox OS,架構是長什麼樣子? 還好 Mozilla 有很多前輩寫了很多資料可以參考很快的我知道 Firefox OS 是由 Gaia, Gecko 以及Gonk 所組成也知道

Gaia: User interface of Firefox OS

Gecko: The “application runtime” of Firefox OS

Gecko: The lower-level “operating system” of Firefox OS

但是我沒有找到文章介紹如何將 Gaia、Gecko Gonk 串起來也就是我想知道整個程式執行 (code flow) 怎樣從 Gaia → Gecko → Gonk,甚至到 Kernel space?

看來看去,Vibration (叫手機震動),是一個還不錯的例子。

它是很簡單,只是單方向由 Gaia 應用程式 (例如:鬧鈴簡訊) 呼叫一個 DOM API 去叫手機震動不需要其他回呼 (call back) 或是等待事件 (event)

我們就以鬧鈴程式裡的計時器為例當倒數計時 timeout, 它會呼叫 DOM API,“navigator.vibrate()”, [200,200,200,200,200] 參數是震動的方式。

gaia/apps/clock/js/timer.js

end: function ti_end() {

  //TODO: ring too

  if (‘vibrate’ in navigator) {

    navigator.vibrate([200, 200, 200, 200, 200]);

  }

  this.cancel();

  this.chronoView.parentNode.classList.add(‘ended’);

},

DOM API “navigator.vibrate” 是被定義在 IDL(Interface Description Language) file, “nsIDOMNavigator.idl”

gecko/dom/interfaces/base/nsIDOMNavigator.idl

interface nsIDOMNavigator : nsISupports

{

   …

   [implicit_jscontext]

   void vibrate(in jsval aPattern);

   …

}

在程式編譯時會根據 “nsIDOMNavigator.idl” 產生 header file

objdir-gecko/dom/interfaces/base/_xpidlgen/nsIDOMNavigator.h”,裡面會定義

NS_IMETHODIMP nsDOMNavigator::Vibrate(const JS::Value & aPattern, JSContext* cx)

注意! 這個地方都有 API 命名的轉換把第一個小寫字母換成大寫,vibrate → Vibrate

接著會呼叫

gecko/dom/base/Navigator.cpp

NS_IMETHODIMP

Navigator::Vibrate(const jsval& aPattern, JSContext* cx)

{

   …

   hal::Vibrate(pattern, domWindow);

   return NS_OK;

}

hal:Vibrate() 會呼叫到 Geckohal

gecko/hal/Hal.cpp

void

Vibrate(const nsTArray& pattern, const WindowIdentifier &id)

{

  …

  hal_impl::Vibrate(pattern, WindowIdentifier());

  …

}

然後接著呼叫 hal 層的 implementation

gecko/hal/gonk/GonkHal.cpp

void

Vibrate(const nsTArray &pattern, const hal::WindowIdentifier &)

{

  MOZ_ASSERT(NS_IsMainThread());

  if (VibratorRunnable::ShuttingDown()) {

    return;

  }

  EnsureVibratorThreadInitialized();

  sVibratorRunnable->Vibrate(pattern);

}

創建 vibrator 執行緒

void

EnsureVibratorThreadInitialized()

{

  if (sVibratorRunnable) {

    return;

  }

  sVibratorRunnable = new VibratorRunnable();

  nsCOMPtr thread;

  NS_NewThread(getter_AddRefs(thread), sVibratorRunnable);

}

丟進 vibrator 執行緒

void

VibratorRunnable::Vibrate(const nsTArray &pattern)

{

  MonitorAutoLock lock(mMonitor);

  mPattern = pattern;

  mIndex = 0;

  mMonitor.Notify();

}

在執行緒裡執行 vibrator_on(),讓馬達震動

NS_IMETHODIMP

VibratorRunnable::Run()

{

  …

  vibrator_on(duration);

  …

  return NS_OK;

}

這時候 Gecko 部分已經完成程式要到 Android HAL

hardware/libhardware_legacy/vibrator/vibrator.cpp

int vibrator_on(int timeout_ms)

{

  /* constant on, up to maximum allowed time */

  return sendit(timeout_ms);

}

這裡的 sendit(),會將馬達開啓的時間長度告訴 Kernel driver.

static int sendit(int timeout_ms)

{

  int nwr, ret, fd;

  char value[20];

  …

  fd = open(THE_DEVICE, O_RDWR);

  if(fd < 0)

    return errno;

  nwr = sprintf(value, “%d\n”, timeout_ms);

  ret = write(fd, value, nwr);

  close(fd);

  return (ret == nwr) ? 0 : -1;

}

到這裡為止手機震動的流程已經完成。