Advertisement

バッテリー監視の為にバックグラウンドタスクについて調べたらなくなってたから作ってみた話のはずだった

マネージャー at 株式会社グローバルサイバーグループ
Dec. 19, 2013
Advertisement

More Related Content

Similar to バッテリー監視の為にバックグラウンドタスクについて調べたらなくなってたから作ってみた話のはずだった(20)

More from Masami Yabushita(19)

Advertisement

バッテリー監視の為にバックグラウンドタスクについて調べたらなくなってたから作ってみた話のはずだった

  1. バッテリー監視の為にバックグラウ ンドタスクについて調べたらなく なってたから作ってみた話 のはずだった 株式会社 グローバルサイバーグループ 藪下 正美
  2. 自己紹介 • 名前 藪下 正美 • 会社 株式会社グローバルサイバーグル ープ • どんな人? – @aoi_nagatsuki – プログラミング言語とかスマホとか好き
  3. 弊社紹介 • 株式会社グローバルサイバーグループ – やる気と人間性を大切にする総合開発企業 – とかはどうでもよくて • ブログやってます – GCG研究所で検索! – ネタ募集中! – 空いてる時に調べてブログに書くのでなんか 聞いてね!
  4. 今日のアジェンダ • バッテリーアプリを作ろうと思った経緯 – バックグラウンドアプリを作ってみた – 最近の環境では動かないと思っていたバックグラ ウンドアプリが動いたので調べてみる事にした • バックグラウンドアプリの仕組み – – – – バックグラウンドサービスマネージャ manifestからいろいろ読み込む frameの保存 frameって何者
  5. 今日のアジェンダ • Gaiaだけだと怒られるのでイベントリス ナを掘り下げてみる – addEventListner – グローバルなwindowオブジェクトを見てみ る – nsEventListenerManager – 各関連イベントは誰がどう投げているのか • mozbrowseropenwindowから掘り下げる • イベントのディスパッチの流れ • イベントディスパッチまとめ
  6. バッテリーアプリを作ろうと思っ た経緯 • 手前味噌ながらここの記事にあるように ある日デバッグビルドを試してみた。 – [Firefox OS][FxOS][Gecko]デバッグ情報 付きのビルド | GCG研究所 – http://www.gcg.bz/labo_blog/?p=504 • デバッグビルドしたsoを端末にプッシュ して動かしているととても電池が減った。 • 電池の減り具合をモニタしたくなった。
  7. バックグラウンドアプリを作って みた • バッテリー監視のためまた手前味噌ながら バックグラウンドアプリを作ってみた。 – バッテリー監視の為にバックグラウンドタスクに ついて調べたらなくなってたから泣く泣くタイ マーAPIを使ってみた話 のはずだった – http://www.slideshare.net/aoitan/api28631339 • この時事前情報として最近のFxOSではバッ クグラウンドアプリは作れないと聞いていた – なので続き物として今回バックグラウンドタスク を作ってみるはずだった • でもやってみると使えてしまった。。。
  8. 最近の環境では動かないと思って いたバックグラウンドアプリが動 いたので調べてみる事にした • 使えてしまったものは仕方ないので予定 を変更してバックグラウンドアプリがど う動くのか見てみた • というのがこれまでのあらすじ
  9. バックグラウンドアプリの仕組み • 本題に入って • バックグラウンドアプリの仕組みは意外 と簡単
  10. バックグラウンドサービスマネー ジャ • systemアプリが起動するときに background_service.jsの BackgroundServiceManagerがwidnowオブ ジェクトにいくつかイベントを登録する – ${B2G}/gaia/apps/system/js/background_serv ice.js window.addEventListener('mozbrowseropenwindow', function bsm_winopen(evt) { window.addEventListener('mozbrowserclose', function bsm_winclose(evt) { window.addEventListener('mozbrowsererror', function bsm_winclose(evt) { window.addEventListener('applicationinstall', function bsm_oninstall(evt) { – window.addEventListener('applicationuninstall', function bsm_oninstall(evt) {
  11. manifestからいろいろ読み込む • applicationinstallのリスナ内で • ```javascript:backgorund_service.js • var appapp = evt.detail.application; var = evt.detail.application; • ``` • なappで • ```javascript:backgorund_service.js • var url = origin + app.manifest.background_page; var url = origin + app.manifest.background_page; • open(manifestURL,AUTO_OPEN_BG_PAGE_NAME, url); open(manifestURL, AUTO_OPEN_BG_PAGE_NAME, • ``` • • • url); な感じの処理をしている。 background_pageにはバックグラウンド動作させたいhtmlのURLが入る。 他にもアプリ名とかとっている
  12. frameの保存 • framesにbackgroundserviceを持つアプリ を集めている • 更にsystemアプリのbodyに入ってる • ```javascript:background_service.js • document.body.appendChild(frame); • ```
  13. frameって何者 • framesに入るのはiframe – 以下のようなオブジェクトが入ってるっぽい • ```javascript frame: { • 'mozbrowser': 'mozbrowser', frame: { • 'mozbrowser': 'mozbrowser', 'mozapp': manifestURL, // アプリのマニフェストのURL • 'mozapp': manifestURL, // アプリのマニフェストのURL 'name': name, // アプリ名 • 'name': name, // アプリ名 • 'remote': true, 'remote': true, • 'src': url, // バックグラウンド動作するHTMLのURL 'src': url, // バックグラウンド動作するHTMLのURL • 'className': 'backgroundWindow', 'className': 'backgroundWindow', • 'dataset': 'dataset': { { • 'frameType': 'background', 'frameType': 'background', • 'frameName': name • 'frameName': name } • } } • ``` }
  14. Gaiaだけだと怒られるのでイベン ト処理を掘り下げてみる • Gecko勉強会でGaiaだけのお話とかなしで すよね。。。 • という事でバックグラウンドアプリ自体の仕 組みは結局の所systemアプリとして動く ページがロードされてるだけっぽいのでバッ クグラウンドサービスマネージャが動くため に必要なイベント処理についてちょっと掘り 下げる。 – と言ってもCOMの中までは終えてないので今後 の課題。
  15. addEventListner再掲 • systemアプリが起動するときにbackground_service.jsの BackgroundServiceManagerがwidnowオブジェクトにいくつかイベン トを登録する • • ``` window.addEventListener('mozbrowseropenwindow', function bsm_winopen(evt) { •window.addEventListener('mozbrowseropenwindow', function window.addEventListener('mozbrowserclose', function bsm_winclose(evt) { bsm_winopen(evt) { •window.addEventListener('mozbrowserclose', function bsm_winclose(evt) { window.addEventListener('mozbrowsererror', function bsm_winclose(evt) { window.addEventListener('mozbrowsererror', function bsm_winclose(evt) { •window.addEventListener('applicationinstall', function bsm_oninstall(evt) { window.addEventListener('applicationinstall', function bsm_oninstall(evt) { window.addEventListener('applicationuninstall', function bsm_oninstall(evt) { • window.addEventListener('applicationuninstall', function bsm_oninstall(evt) { • ```
  16. グローバルなwindow オブジェクトを見てみる • グローバルオブジェクトのwindowにぶら下がっている addEventListenerなので – cpp:gecko/dom/base/nsGlobalWindow.cppあたりにいるはず • ```cpp:gecko/dom/base/nsGlobalWindow.cpp NS_IMETHODIMP • NS_IMETHODIMP nsGlobalWindow::AddEventListener(const nsAString& aType, • nsGlobalWindow::AddEventListener(const nsAString& aType, nsIDOMEventListener *aListener, • nsIDOMEventListener *aListener, bool aUseCapture, bool aWantsUntrusted, • bool aUseCapture, bool aWantsUntrusted, uint8_t aOptionalArgc) • uint8_t aOptionalArgc) • ``` – こんなのがいた
  17. グローバルなwindow オブジェクトを見てみる – キモはこれ • ```cpp:gecko/dom/base/nsGlobalWindow.cp p •nsEventListenerManager* manager nsEventListenerManager* manager = = GetListenerManager(true); GetListenerManager(true); NS_ENSURE_STATE(manager); • manager->AddEventListener(aType, aListener, aUseCapture, NS_ENSURE_STATE(manager); aWantsUntrusted); • manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); • ```
  18. グローバルなwindow オブジェクトを見てみる – 要するにイベントリスナマネージャとやらに AddEventListenerしている • ```cpp:gecko/content/events/src/nsEventListenerMan ager.cpp void • void nsEventListenerManager::AddEventListener(nsIDOMEventListener • nsEventListenerManager::AddEventListener(nsIDOME *aListener, ventListener *aListener, uint32_t aType, • uint32_t aType, nsIAtom* aTypeAtom, int32_t aFlags, • nsIAtom* aTypeAtom, bool aHandler) • int32_t aFlags, • bool aHandler) • ```
  19. nsEventListenerManager • • • • • • • • • • • ぱっと見すごく長いけどイベントリスナマネージャのAddEventListener では以下の部分がキモ ```cpp:gecko/content/events/src/nsEventListenerManager.cpp ls =ls = mListeners.AppendElement(); mListeners.AppendElement(); ls->mListener = aListener; ls->mListener = aListener; ls->mEventType = aType; ls->mEventType = aType; ls->mTypeAtom = aTypeAtom; ls->mTypeAtom = aTypeAtom; ls->mFlags = aFlags; ls->mFlags = aFlags; ls->mListenerIsHandler = aHandler; ls->mListenerIsHandler = aHandler; ls->mHandlerIsString = false; ls->mHandlerIsString = false; ``` 要するにリスナの配列に渡されたリスナを格納してるだけ – メソッド全体で長いのはフラグとかタイプによって後処理を変えたりするための値の 加工と保持とか別のイベントリスナへの登録とか
  20. 各関連イベントは誰がどう投げ ているのか
  21. Mozbrowseropenwindow から掘り下げる • gecko/dom/browserelement/BrowserElementParent.cppに DispatchOpenWindowEventがいる • キモの部分は • ```cpp:gecko/dom/browserelement/BrowserElementParent.cpp •boolbool dispatchSucceeded = dispatchSucceeded = • DispatchCustomDOMEvent(aOpenerFrameElement, DispatchCustomDOMEvent(aOpenerFrameElement, NS_LITERAL_STRING("mozbrowseropenwindow"), • detail); NS_LITERAL_STRING("mozbrowseropenwindow"), • detail); • ```
  22. Mozbrowseropenwindow から掘り下げる • そのDispatchCustomDOMEventはこんな感じ • ```cpp:gecko/dom/browserelement/BrowserElementParent.cpp •nsEventDispatcher::CreateEvent(presContext, nullptr, nullptr, nsEventDispatcher::CreateEvent(presContext, NS_LITERAL_STRING("customevent"), • NS_LITERAL_STRING("customevent"), getter_AddRefs(domEvent)); • getter_AddRefs(domEvent)); • ``` • ```cpp:gecko/dom/browserelement/BrowserElementParent.cpp •nsCOMPtr<nsIDOMCustomEvent> customEvent = nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent); do_QueryInterface(domEvent); • ```
  23. Mozbrowseropenwindow から掘り下げる • ```cpp:gecko/dom/browser-element/BrowserElementParent.cpp • customEvent->InitCustomEvent(aEventName, •customEvent->InitCustomEvent(aEventName, /* bubbles = */ true, /* bubbles = */ true, false, • /* cancelable = */ /* cancelable = */ false, • detailVariant); detailVariant); • customEvent->SetTrusted(true); • customEvent->SetTrusted(true); // Dispatch the event. • // Dispatch the event. nsEventStatus status = nsEventStatus_eIgnore; • nsEventStatus status = nsEventStatus_eIgnore; rv = nsEventDispatcher::DispatchDOMEvent(aFrameElement, rv = nsEventDispatcher::DispatchDOMEvent(aFrameElement, nullptr, nullptr, domEvent, presContext, &status); • domEvent, presContext, &status); • ``` • カスタムイベントオブジェクトを作ってDispatchDOMEventしている
  24. イベントのディスパッチの流れ • DispatchCustomDOMEventで呼ばれている nsEventDispatcher::DispatchDOMEventから • ```cpp:gecko/content/events/src/nsEventDispatcher.cpp • return nsEventDispatcher::Dispatch(aTarget, return nsEventDispatcher::Dispatch(aTarget, aPresContext, innerEvent, aPresContext, innerEvent, • aDOMEvent, aEventStatus); aDOMEvent, aEventStatus); • } else if (aEvent) { } else if (aEvent) { • return nsEventDispatcher::Dispatch(aTarget, return nsEventDispatcher::Dispatch(aTarget, aPresContext, aEvent, aPresContext, aEvent, • aDOMEvent, aEventStatus); aDOMEvent, aEventStatus); • ``` • こんなかんじでDispatchが呼ばれて
  25. イベントのディスパッチの流れ • ```cpp:gecko/content/events/src/nsEventDispatcher.cpp • /* static */ nsresult /* nsEventDispatcher::Dispatch(nsISupports* aTarget, • static */ nsresult nsEventDispatcher::Dispatch(nsISupports* aTarget, • nsPresContext* aPresContext, nsPresContext* aPresContext, • nsEvent* aEvent, nsEvent* aEvent, • nsIDOMEvent* aDOMEvent, nsIDOMEvent* aDOMEvent, • nsEventStatus* aEventStatus, nsEventStatus* aEventStatus, • nsDispatchingCallback* aCallback, nsDispatchingCallback* aCallback, • nsCOMArray<nsIDOMEventTarget>* nsCOMArray<nsIDOMEventTarget>* aTargets) { aTargets) • めっちゃ長い! { } • めっちゃ長い! • } • ```
  26. イベントディスパッチまとめ • 時間切れで追いきれてませんがざっくり見た 感じ – カスタムイベントのオブジェクトから DispatchCustomEventされると – nsEventDispatcherのDispatchまで流れてくる – nsEventDispatcher::Dispatchでは • イベントのオブジェクトを作る (topEtci等々) • 送信先のリストを作る (postVisitor) – 対象のDOM要素から親へ親へたどってる? » 教えてエライ人!
  27. イベントディスパッチまとめ • ```cpp:gecko/content/events/src/nsEventDispatcher.c pp • rv = topEtci>HandleEventTargetChain(postVisitor, • rv = topEtci->HandleEventTargetChain(postVisitor, NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_BUBBLE | • NS_EVENT_FLAG_CAPTURE, NS_EVENT_FLAG_CAPTURE, aCallback, • aCallback, false, &pusher); • false, • &pusher); • ```
  28. イベントディスパッチまとめ • でpostVisitorに詰めた配信対象のDOM要素に対 してイベントオブジェクトを投げつけていくはず – 教えてエライ人! – mozbrowseropenwindow以外のイベント が見つからないけどカスタムイベントじゃな いから? • 教えてエライ人!
Advertisement