この記事は『Firefox OS / B2G OS Advent Calendar 2016』 12日目の記事です。
Firefox OS で、使用されている「ADB Helper」を再度まとめ直してみました。
前回、新訳:ADB Helperをハックしてみた(install.rdf,main.js)に引き続き、 adb-helperをハックしていきたいと思います
※2 : version 0.7.1 時点で有ったファイル
※3 : version 0.7.1 時点で有ったファイル、Windows用ファイル
※4 : version 0.7.1 時点で有ったファイル、mac,linux用ファイル
OS毎に使用されるファイルが有る事が確認できます。
-
Strict モード(use strict)
ECMAScript 5 の strict モードは、JavaScript の制限された異形にオプトインする方法です。 strict モードは単なるサブセットではありません: strict モードは意図的に、通常モードとは異なる意味を持っています。 strict モードをサポートしないブラウザは、strict モードのコードについて サポートするブラウザとは異なる動作をする可能性がありますので、 strict モードに関する側面をサポートするかの機能テストを行わずに strict モードを頼らないでください。 strict モードのコードと非 strict モードのコードは共存できますので、 スクリプトを順次 strict モードにオプトインすることができます。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Strict_mode
-
let 文
let 文は変数に対するローカルスコープを提供します。 let 文はコードのある 1 つのブロックのレキシカルスコープに 0 以上の変数を 結びつけることによって働き、それ以外はブロック文と全く同じです。 特に、let 文の内側で var を使って定義された変数のスコープは、 let 文の外側でそれが定義された場合と同じであり、 そのような変数は従来通り関数スコープを持つことに注意してください。 https://developer.mozilla.org/ja/docs/Web/JavaScript/New_in_JavaScript/1.7#let_.E6.96.87
-
module
module 現在のモジュールへの参照です。 特に module.exports は exports オブジェクトと同じです。 より詳しくは src/node.js を参照してください。 module は実際はグローバルではなく、各モジュール毎のローカルです。 http://d.hatena.ne.jp/jovi0608/20111226/1324879536
-
JavaScript コードモジュールの利用(jsm)
JavaScript コードモジュールは、Gecko 1.9 で導入されたコンセプトであり、 特権を持った異なるスコープ間でコードを共有するために用いられます。 また、モジュールは、グローバルな JavaScript のシングルトンオブジェクトを 生成するために用いることもできます (以前は JavaScript XPCOM オブジェクトを使う必要がありました)。 JavaScript コードモジュールは、登録されたパスに配置された純粋な JavaScript のコードです。 Components.utils.import() を使って、 XUL スクリプトや JavaScript XPCOM スクリプトのような 特定のJavaScript のスコープへモジュールを読み込むことができます。 https://developer.mozilla.org/ja/docs/Mozilla/JavaScript_code_modules/Using
-
subprocess
subprocess subprocess.jsm - start a process in your Firefox Extension and read/write data to/from it using stdin/stdout/stderr streams. https://github.com/bit/subprocess
- Cc, Ci, Cu, Cr にchrome ライブラリ読み込み
- subprocess にライブラリ読み込み
- file にライブラリ読み込み
- env にライブラリ読み込み
- XPCOMABI にライブラリ読み込み
- setTimeout にライブラリ読み込み
- client を用いて、adb-client.js を読み込み
- Cu, TextEncoder, TextDecoder に Services.jsm をインポート
- 変数 promise に Promise.jsm を代入
- Cu に OS.File for the main thread をインポート
ADB オブジェクト
- didRunInitially() プロパティ
- ready() プロパティ
- adb_init() 関数
- adb_start() 関数
- stop() 関数
- adb_kill() 関数
- _isAdbRunning() 関数
- adb_trackDevices() 関数
- adb_listDevices() 関数
- adb_forwardPort() 関数
- adb_checkFileMode() 関数
- adb_pull() 関数
- adb_push() 関数
- adb_shell() 関数
- adb_reboot() 関数
- adb_rebootRecovery() 関数
- rebootBootloader() 関数
- adb_root() 関数
- adb_runCommand() 関数
- platform に Services.appinfo.OS を代入
- uri に resource://adbhelperatmozilla.org/ 代入
- platform の条件分岐(OS 毎)
- 上記結果を元に Services.io.newURI 用いて url を取得
- コメント
adb をサーバーモードで起動させ、tcp ソケット参照を true にする - Deferred オブジェクト deferred を promise.defer() 用いて生成
- 通知用オブザーバ onSuccessfulStart を定義
- adb-ready で、Services.obs.notifyObservers を呼出
- adb-running-checker.js を読み込み
- isAdbRunning = true の時、 onSuccessfulStart() 実行
- nsIProcess(@mozilla.org/process/util;1) で、process を定義
- 初期化処理 process.init() 実行
- 同期処理 process.runAsync() を実行
- deferred を return
- コメント
adb サーバーが動作している時だけを停止します。
起動前に使用した場合、immediately を返します。 - 引数:sync を用いて、adb サーバーを停止させます
- コメント
adb サーバーを Kill します。
adb サーバーが再度起動した時、引数:aSync を渡します。
- nsIProcess(@mozilla.org/process/util;1) で、process を定義
- aSync 判定
- true の時、process.run() 実行
- false の時、同期処理 process.runAsync() を実行
- platform に Services.appinfo.OS を代入
- Deferred オブジェクト deferred を promise.defer() 用いて生成
- platform 判定
- WINNT の時、変数 ps に "C:\\windows\\system32\\tasklist.exe" をセット
- 上記以外 の時、file.exists() を使用して 変数 ps に値をセット
- 変数 ps を用いて、サブプロセス subprocess 呼出
- コメント
デバイスの接続/切断をトレースします。
ソケットが繋がっている間、再利用できません。 - adb-client.js の connect() 呼出
- 引数:"adb-track-devices-start" で、
関数 socket.s.onopen を定義し、同期 - 引数:"adb-track-devices-stop" で、
関数 socket.s.onerror を定義し、同期 - 引数:"adb-track-devices-stop" で、
関数 socket.s.onclose を定義し、同期 - 関数 socket.s.ondata を定義し、同期
- adb-client.js の checkResponse() 呼出
- adb-client.js の unpackPacket() 呼出、変数 packet へ代入
- packet.data を判定し、events.emit() を実行
- コメント
デバイス名の配列を返します。
- runCommand を実行し、データ取得成功時に
デバイス名を配列に格納します。
- runCommand を実行し、データ取得成功時に
データを返します。
- コメント
ファイルのモードをチェックします。
- チェック用配列:masks を定義
- チェック用配列:masks に該当する値が無い時、false を返します。
- 上記以外の時、チェック用配列:masks に該当する値を返します
- コメント
デバイスからファイルを pull します。
- Deferred オブジェクト deferred を promise.defer() 用いて生成
- 各種変数を定義
- 関数 shutdown を定義します。
- adb-client.js の close() 呼出
- deferred.reject() を実行します。
- 関数 extractChunkDataHeader を定義します。
- 配列変数:headerArray を初期化します
- 配列変数:headerArray に引数data を代入します。
- 関数 checkChunkDataHeader を定義します。
- データ長 + 現在のヘッダ長 > 8 バイト以上の時、
以下の処理を実行します。 - 関数 extractChunkDataHeader を実行します。
- 配列変数:headerArray[0] と定数:DATAが不一致の時、shutdown() を実行し、false を返します。
- ヘッダの長さにデータ長を加算します。
- true を返します。
- データ長 + 現在のヘッダ長 > 8 バイト以上の時、
- 関数 checkDone を定義します。
- データ長が 8 バイト以外の時、false を返します。
- 配列変数:doneFlagArray を Uint32Array で、定義します。
- 配列変数:doneFlagArray[0] が定数:DONE の時、
true を返します。 - 上記以外の時、false を返します。
- 関数 runFSM を定義します。
- 変数:state を判定し、状態毎の処理を実行します。
- 関数 setupSocket を定義します。
- 関数 socket.s.onerror を定義し、引数:"SOCKET_ERROR" で、deferred.reject() を実行します。
- 関数 socket.s.onopen を定義し、関数runFSM() を実行します。
- 関数 socket.s.onclose を定義します。
- 関数 socket.s.ondata を定義し、関数runFSM() を実行します。
- adb-client.js の connect() 呼出
- 関数 setupSocket() を実行します。
- deferred を return
- コメント
ファイルをデバイスへ push します。
- Deferred オブジェクト deferred を promise.defer() 用いて生成
- 各種変数を定義
- 関数 shutdown を定義します。
- adb-client.js の close() 呼出
- deferred.reject() を実行します。
- 関数 runFSM を定義します。
- 変数:state を判定し、状態毎の処理を実行します。
- 関数 setupSocket を定義します。
- 関数 socket.s.onerror を定義し、引数:"SOCKET_ERROR" で、deferred.reject() を実行します。
- 関数 socket.s.onopen を定義し、関数runFSM() を実行します。
- 関数 socket.s.onclose を定義します。
- 関数 socket.s.ondata を定義し、関数runFSM() を実行します。
- 関数 OS.File.stat() を実行します。
- ファイル情報取得成功時、以下の処理を実行します。
- 取得情報がディレクトリの場合、deferred.reject() を実行します。
- 取得情報がファイルの場合、 ファイル情報を格納します。
- ファイル情報取得失敗時、deferred.reject() を実行します。
- deferred を return
- コメント
ファイルをデバイスへ push します。
- Deferred オブジェクト deferred を promise.defer() 用いて生成
- 各種変数を定義
- 関数 shutdown を定義します。
- adb-client.js の close() 呼出
- deferred.reject() を実行します。
- 関数 runFSM を定義します。
- 変数:state を判定し、状態毎の処理を実行します。
- adb-client.js の connect() 呼出
- 関数 socket.s.onerror を定義し、引数:"SOCKET_ERROR" で、deferred.reject() を実行します。
- 関数 socket.s.onopen を定義し、関数runFSM() を実行します。
- 関数 socket.s.onclose を定義します。
- 関数 socket.s.ondata を定義し、関数runFSM() を実行します。
- deferred を return
- shell() を実行します。
- shell() を実行します。
- shell() を実行します。
- Deferred オブジェクト deferred を promise.defer() 用いて生成
- 各種変数を定義
- 関数 shutdown を定義します。
- adb-client.js の close() 呼出
- deferred.reject() を実行します。
- 関数 runFSM を定義します。
- 変数:state を判定し、状態毎の処理を実行します。
- adb-client.js の connect() 呼出
- 関数 socket.s.onerror を定義し、引数:"SOCKET_ERROR" で、deferred.reject() を実行します。
- 関数 socket.s.onopen を定義し、関数runFSM() を実行します。
- 関数 socket.s.onclose を定義し、deferred.resolve() を実行します。
- 関数 socket.s.ondata を定義し、関数runFSM() を実行します。
- deferred を return
- コメント
非同期的に adb コマンドを実行します。
- Deferred オブジェクト deferred を promise.defer() 用いて生成
- プロパティ:ready = false の時、以下の処理を実行します。
- 関数:setTimeout を用いて、deferred.reject() を実行します。
- deferred を return
- adb-client.js の connect() 呼出
- 関数 socket.s.onopen を定義し、同期します。
- adb-client.js の createRequest() 呼出
- adb コマンドを送信します。
- 関数 socket.s.onerror を定義し、deferred.reject() を実行します。
- 関数 socket.s.onclose を定義します。
- 関数 socket.s.ondata を定義し、同期
- adb-client.js の unpackPacket() 呼出
- adb-client.js の unpackPacket() 呼出、変数 packet へ代入
- packet.data を判定し、deferred.reject() を実行します。
- deferred.resolve() を実行します。
- deferred を return
かなり長いブログになってしまったので、ご覧になる方にどう映るか些か心配です。
初めて見る方のソースコード解析のお役に立てば、幸いです。
次回は、adb-client.js をハックする予定です。