28
バッテリー監視の為にバックグラウ ンドタスクについて調べたらなく なってたから作ってみた話 のはずだった 株式会社 グローバルサイバーグループ 藪下 正美

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

Embed Size (px)

DESCRIPTION

 

Citation preview

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

バッテリー監視の為にバックグラウンドタスクについて調べたらなく

なってたから作ってみた話 のはずだった

株式会社

グローバルサイバーグループ

藪下 正美

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

自己紹介

• 名前 藪下 正美

• 会社 株式会社グローバルサイバーグループ

• どんな人?

– @aoi_nagatsuki

–プログラミング言語とかスマホとか好き

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

弊社紹介

• 株式会社グローバルサイバーグループ

–やる気と人間性を大切にする総合開発企業

–とかはどうでもよくて

• ブログやってます

–GCG研究所で検索!

–ネタ募集中!

–空いてる時に調べてブログに書くのでなんか聞いてね!

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

今日のアジェンダ

• バッテリーアプリを作ろうと思った経緯

– バックグラウンドアプリを作ってみた

– 最近の環境では動かないと思っていたバックグラウンドアプリが動いたので調べてみる事にした

• バックグラウンドアプリの仕組み

– バックグラウンドサービスマネージャ

– manifestからいろいろ読み込む

– frameの保存

– frameって何者

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

今日のアジェンダ

• Gaiaだけだと怒られるのでイベントリスナを掘り下げてみる – addEventListner

–グローバルなwindowオブジェクトを見てみる

– nsEventListenerManager

–各関連イベントは誰がどう投げているのか • mozbrowseropenwindowから掘り下げる

• イベントのディスパッチの流れ

• イベントディスパッチまとめ

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

バッテリーアプリを作ろうと思った経緯

• 手前味噌ながらここの記事にあるようにある日デバッグビルドを試してみた。

– [Firefox OS][FxOS][Gecko]デバッグ情報付きのビルド | GCG研究所

– http://www.gcg.bz/labo_blog/?p=504

• デバッグビルドしたsoを端末にプッシュして動かしているととても電池が減った。

• 電池の減り具合をモニタしたくなった。

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

バックグラウンドアプリを作ってみた

• バッテリー監視のためまた手前味噌ながらバックグラウンドアプリを作ってみた。 – バッテリー監視の為にバックグラウンドタスクについて調べたらなくなってたから泣く泣くタイマーAPIを使ってみた話 のはずだった

– http://www.slideshare.net/aoitan/api-28631339

• この時事前情報として最近のFxOSではバックグラウンドアプリは作れないと聞いていた – なので続き物として今回バックグラウンドタスクを作ってみるはずだった

• でもやってみると使えてしまった。。。

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

最近の環境では動かないと思っていたバックグラウンドアプリが動いたので調べてみる事にした

• 使えてしまったものは仕方ないので予定を変更してバックグラウンドアプリがどう動くのか見てみた

• というのがこれまでのあらすじ

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

バックグラウンドアプリの仕組み

• 本題に入って

• バックグラウンドアプリの仕組みは意外と簡単

Page 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) {

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

manifestからいろいろ読み込む

• applicationinstallのリスナ内で

• ```javascript:backgorund_service.js • var app = evt.detail.application; • ```

• なappで

• ```javascript:backgorund_service.js • var url = origin + app.manifest.background_page; • open(manifestURL, AUTO_OPEN_BG_PAGE_NAME, url); • ```

• な感じの処理をしている。 • background_pageにはバックグラウンド動作させたいhtmlのURLが入る。 • 他にもアプリ名とかとっている

var app = evt.detail.application;

var url = origin + app.manifest.background_page; open(manifestURL, AUTO_OPEN_BG_PAGE_NAME, url);

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

frameの保存

• framesにbackgroundserviceを持つアプリを集めている

• 更にsystemアプリのbodyに入ってる

• ```javascript:background_service.js

• document.body.appendChild(frame);

• ```

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

frameって何者

• framesに入るのはiframe

– 以下のようなオブジェクトが入ってるっぽい

• ```javascript • frame: { • 'mozbrowser': 'mozbrowser', • 'mozapp': manifestURL, // アプリのマニフェストのURL • 'name': name, // アプリ名 • 'remote': true, • 'src': url, // バックグラウンド動作するHTMLのURL • 'className': 'backgroundWindow', • 'dataset': { • 'frameType': 'background', • 'frameName': name • } • } • ```

frame: { 'mozbrowser': 'mozbrowser', 'mozapp': manifestURL, // アプリのマニフェストのURL 'name': name, // アプリ名 'remote': true, 'src': url, // バックグラウンド動作するHTMLのURL 'className': 'backgroundWindow', 'dataset': { 'frameType': 'background', 'frameName': name } }

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

Gaiaだけだと怒られるのでイベント処理を掘り下げてみる

• Gecko勉強会でGaiaだけのお話とかなしですよね。。。

• という事でバックグラウンドアプリ自体の仕組みは結局の所systemアプリとして動くページがロードされてるだけっぽいのでバックグラウンドサービスマネージャが動くために必要なイベント処理についてちょっと掘り下げる。 – と言ってもCOMの中までは終えてないので今後の課題。

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

addEventListner再掲

• systemアプリが起動するときにbackground_service.jsの

BackgroundServiceManagerがwidnowオブジェクトにいくつかイベントを登録する

• ``` • 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) { • ```

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) {

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

グローバルなwindow オブジェクトを見てみる

• グローバルオブジェクトのwindowにぶら下がっている

addEventListenerなので – cpp:gecko/dom/base/nsGlobalWindow.cppあたりにいるはず

• ```cpp:gecko/dom/base/nsGlobalWindow.cpp • NS_IMETHODIMP • nsGlobalWindow::AddEventListener(const nsAString& aType, • nsIDOMEventListener *aListener, • bool aUseCapture, bool aWantsUntrusted, • uint8_t aOptionalArgc) • ```

– こんなのがいた

NS_IMETHODIMP nsGlobalWindow::AddEventListener(const nsAString& aType, nsIDOMEventListener *aListener, bool aUseCapture, bool aWantsUntrusted, uint8_t aOptionalArgc)

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

グローバルなwindow オブジェクトを見てみる

– キモはこれ

```cpp:gecko/dom/base/nsGlobalWindow.cpp

• nsEventListenerManager* manager = GetListenerManager(true);

• NS_ENSURE_STATE(manager); • manager->AddEventListener(aType,

aListener, aUseCapture, aWantsUntrusted); • ```

nsEventListenerManager* manager = GetListenerManager(true); NS_ENSURE_STATE(manager); manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);

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

グローバルなwindow オブジェクトを見てみる

– 要するにイベントリスナマネージャとやらにAddEventListenerしている

```cpp:gecko/content/events/src/nsEventListenerManager.cpp

• void • nsEventListenerManager::AddEventListener(nsIDOME

ventListener *aListener, • uint32_t aType, • nsIAtom* aTypeAtom, • int32_t aFlags, • bool aHandler) • ```

void nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener, uint32_t aType, nsIAtom* aTypeAtom, int32_t aFlags, bool aHandler)

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

nsEventListenerManager

• ぱっと見すごく長いけどイベントリスナマネージャのAddEventListenerでは以下の部分がキモ

• ```cpp:gecko/content/events/src/nsEventListenerManager.cpp • ls = mListeners.AppendElement(); • ls->mListener = aListener; • ls->mEventType = aType; • ls->mTypeAtom = aTypeAtom; • ls->mFlags = aFlags; • ls->mListenerIsHandler = aHandler; • ls->mHandlerIsString = false; • ```

• 要するにリスナの配列に渡されたリスナを格納してるだけ

– メソッド全体で長いのはフラグとかタイプによって後処理を変えたりするための値の加工と保持とか別のイベントリスナへの登録とか

ls = mListeners.AppendElement(); ls->mListener = aListener; ls->mEventType = aType; ls->mTypeAtom = aTypeAtom; ls->mFlags = aFlags; ls->mListenerIsHandler = aHandler; ls->mHandlerIsString = false;

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

各関連イベントは誰がどう投げているのか

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

Mozbrowseropenwindow から掘り下げる

• gecko/dom/browser-

element/BrowserElementParent.cppにDispatchOpenWindowEventがいる

• キモの部分は

• ```cpp:gecko/dom/browser-element/BrowserElementParent.cpp

• bool dispatchSucceeded = • DispatchCustomDOMEvent(aOpenerFrameElement, •

NS_LITERAL_STRING("mozbrowseropenwindow"), • detail); • ```

bool dispatchSucceeded = DispatchCustomDOMEvent(aOpenerFrameElement, NS_LITERAL_STRING("mozbrowseropenwindow"), detail);

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

Mozbrowseropenwindow から掘り下げる

• そのDispatchCustomDOMEventはこんな感じ

• ```cpp:gecko/dom/browser-element/BrowserElementParent.cpp

• nsEventDispatcher::CreateEvent(presContext, nullptr, • NS_LITERAL_STRING("customevent"), • getter_AddRefs(domEvent)); • ```

• ```cpp:gecko/dom/browser-

element/BrowserElementParent.cpp • nsCOMPtr<nsIDOMCustomEvent> customEvent =

do_QueryInterface(domEvent); • ```

nsEventDispatcher::CreateEvent(presContext, nullptr, NS_LITERAL_STRING("customevent"), getter_AddRefs(domEvent));

nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);

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

Mozbrowseropenwindow から掘り下げる

• ```cpp:gecko/dom/browser-element/BrowserElementParent.cpp • customEvent->InitCustomEvent(aEventName, • /* bubbles = */ true, • /* cancelable = */ false, • detailVariant); • customEvent->SetTrusted(true); • // Dispatch the event. • nsEventStatus status = nsEventStatus_eIgnore; • rv = nsEventDispatcher::DispatchDOMEvent(aFrameElement,

nullptr, • domEvent, presContext, &status); • ```

• カスタムイベントオブジェクトを作ってDispatchDOMEventしている

customEvent->InitCustomEvent(aEventName, /* bubbles = */ true, /* cancelable = */ false, detailVariant); customEvent->SetTrusted(true); // Dispatch the event. nsEventStatus status = nsEventStatus_eIgnore; rv = nsEventDispatcher::DispatchDOMEvent(aFrameElement, nullptr, domEvent, presContext, &status);

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

イベントのディスパッチの流れ

• DispatchCustomDOMEventで呼ばれているnsEventDispatcher::DispatchDOMEventから

• ```cpp:gecko/content/events/src/nsEventDispatcher.cpp • return nsEventDispatcher::Dispatch(aTarget,

aPresContext, innerEvent, • aDOMEvent, aEventStatus); • } else if (aEvent) { • return nsEventDispatcher::Dispatch(aTarget,

aPresContext, aEvent, • aDOMEvent, aEventStatus); • ```

• こんなかんじでDispatchが呼ばれて

return nsEventDispatcher::Dispatch(aTarget, aPresContext, innerEvent, aDOMEvent, aEventStatus); } else if (aEvent) { return nsEventDispatcher::Dispatch(aTarget, aPresContext, aEvent, aDOMEvent, aEventStatus);

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

イベントのディスパッチの流れ

• ```cpp:gecko/content/events/src/nsEventDispatcher.cpp • /* static */ nsresult • nsEventDispatcher::Dispatch(nsISupports* aTarget, • nsPresContext* aPresContext, • nsEvent* aEvent, • nsIDOMEvent* aDOMEvent, • nsEventStatus* aEventStatus, • nsDispatchingCallback* aCallback, • nsCOMArray<nsIDOMEventTarget>*

aTargets) • { • めっちゃ長い! • } • ```

/* static */ nsresult nsEventDispatcher::Dispatch(nsISupports* aTarget, nsPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent* aDOMEvent, nsEventStatus* aEventStatus, nsDispatchingCallback* aCallback, nsCOMArray<nsIDOMEventTarget>* aTargets) { めっちゃ長い! }

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

イベントディスパッチまとめ

• 時間切れで追いきれてませんがざっくり見た感じ

– カスタムイベントのオブジェクトからDispatchCustomEventされると

– nsEventDispatcherのDispatchまで流れてくる

– nsEventDispatcher::Dispatchでは • イベントのオブジェクトを作る (topEtci等々)

• 送信先のリストを作る (postVisitor)

– 対象のDOM要素から親へ親へたどってる?

» 教えてエライ人!

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

イベントディスパッチまとめ

• ```cpp:gecko/content/events/src/nsEventDispatcher.cpp

• rv = topEtci->HandleEventTargetChain(postVisitor,

• NS_EVENT_FLAG_BUBBLE |

• NS_EVENT_FLAG_CAPTURE,

• aCallback, • false, • &pusher); • ```

rv = topEtci->HandleEventTargetChain(postVisitor, NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE, aCallback, false, &pusher);

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

イベントディスパッチまとめ

• でpostVisitorに詰めた配信対象のDOM要素に対してイベントオブジェクトを投げつけていくはず – 教えてエライ人!

– mozbrowseropenwindow以外のイベントが見つからないけどカスタムイベントじゃないから?

• 教えてエライ人!