狠狠撸

狠狠撸Share a Scribd company logo
バッテリー監視の為にバックグラウ
ンドタスクについて調べたらなく
なってたから作ってみた話
のはずだった
株式会社
グローバルサイバーグループ
藪下 正美
自己紹介
? 名前 藪下 正美
? 会社 株式会社グローバルサイバーグル
ープ
? どんな人?
– @aoi_nagatsuki
– プログラミング言語とかスマホとか好き
弊社紹介
? 株式会社グローバルサイバーグループ
– やる気と人間性を大切にする総合開発企業
– とかはどうでもよくて

? ブログやってます
– GCG研究所で検索!
– ネタ募集中!
– 空いてる時に調べてブログに書くのでなんか
聞いてね!
今日のアジェンダ
? バッテリーアプリを作ろうと思った経緯
– バックグラウンドアプリを作ってみた
– 最近の環境では動かないと思っていたバックグラ
ウンドアプリが動いたので調べてみる事にした

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

バックグラウンドサービスマネージャ
manifestからいろいろ読み込む
frameの保存
frameって何者
今日のアジェンダ
? Gaiaだけだと怒られるのでイベントリス
ナを掘り下げてみる
– addEventListner
– グローバルなwindowオブジェクトを見てみ
る
– nsEventListenerManager
– 各関連イベントは誰がどう投げているのか
? mozbrowseropenwindowから掘り下げる
? イベントのディスパッチの流れ
? イベントディスパッチまとめ
バッテリーアプリを作ろうと思っ
た経緯
? 手前味噌ながらここの記事にあるように
ある日デバッグビルドを試してみた。
– [Firefox OS][FxOS][Gecko]デバッグ情報
付きのビルド | GCG研究所
– http://www.gcg.bz/labo_blog/?p=504

? デバッグビルドしたsoを端末にプッシュ
して動かしているととても電池が減った。
? 電池の減り具合をモニタしたくなった。
バックグラウンドアプリを作って
みた
? バッテリー監視のためまた手前味噌ながら
バックグラウンドアプリを作ってみた。
– バッテリー監視の為にバックグラウンドタスクに
ついて調べたらなくなってたから泣く泣くタイ
マーAPIを使ってみた話 のはずだった
– http://www.slideshare.net/aoitan/api28631339

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

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

? 使えてしまったものは仕方ないので予定
を変更してバックグラウンドアプリがど
う動くのか見てみた
? というのがこれまでのあらすじ
バックグラウンドアプリの仕組み
? 本題に入って
? バックグラウンドアプリの仕組みは意外
と簡単
バックグラウンドサービスマネー
ジャ
? 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) {
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が入る。
他にもアプリ名とかとっている
frameの保存
? framesにbackgroundserviceを持つアプリ
を集めている
? 更にsystemアプリのbodyに入ってる

? ```javascript:background_service.js
?
document.body.appendChild(frame);
? ```
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
}
? } }
? ```
}
Gaiaだけだと怒られるのでイベン
ト処理を掘り下げてみる
? Gecko勉強会でGaiaだけのお話とかなしで
すよね。。。
? という事でバックグラウンドアプリ自体の仕
組みは結局の所systemアプリとして動く
ページがロードされてるだけっぽいのでバッ
クグラウンドサービスマネージャが動くため
に必要なイベント処理についてちょっと掘り
下げる。
– と言ってもCOMの中までは終えてないので今後
の課題。
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) {
? ```
グローバルな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)
?
```
– こんなのがいた
グローバルな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);
?
```
グローバルな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)
?
```
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;
```
要するにリスナの配列に渡されたリスナを格納してるだけ
– メソッド全体で長いのはフラグとかタイプによって後処理を変えたりするための値の
加工と保持とか別のイベントリスナへの登録とか
各関連イベントは誰がどう投げ
ているのか
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);
?
```
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);
?
```
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している
イベントのディスパッチの流れ
? 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が呼ばれて
イベントのディスパッチの流れ
?
```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)
? めっちゃ長い!
{
}
?
めっちゃ長い!
? }
?
```
イベントディスパッチまとめ
? 時間切れで追いきれてませんがざっくり見た
感じ
– カスタムイベントのオブジェクトから
DispatchCustomEventされると
– nsEventDispatcherのDispatchまで流れてくる
– nsEventDispatcher::Dispatchでは
? イベントのオブジェクトを作る (topEtci等々)
? 送信先のリストを作る (postVisitor)
– 対象のDOM要素から親へ親へたどってる?
? 教えてエライ人!
イベントディスパッチまとめ
?

```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);
?
```
イベントディスパッチまとめ
? でpostVisitorに詰めた配信対象のDOM要素に対
してイベントオブジェクトを投げつけていくはず
– 教えてエライ人!

– mozbrowseropenwindow以外のイベント
が見つからないけどカスタムイベントじゃな
いから?
? 教えてエライ人!

More Related Content

バッテリー监视の為にバックグラウンドタスクについて调べたらなくなってたから作ってみた话のはずだった