らいふうっどの閑話休題

興味のあることをゆる~く書いていく

ADB Helperをハックしてみた(adb.js篇)

目次

前回:ADB Helperをハックしてみた(install.rdf,main.js篇)に引き続き、 adb-helperをハックしていきたいと思います

  1. フォルダ内のファイル構成
  2. adb.js
  3. 予備知識
  4. モジュール構成
  5. 今回のまとめ

フォルダ内のファイル構成
[解凍フォルダ内のjsファイル群]
windowsmaclinux
install.rdf
main.js
adb.js
adb-client.js
adb-running-checker.js
adb-socket.js
bootstrap.js
scanner.js
subprocess.js
subprocess_worker_unix.js
subprocess_worker_win.js

前回に引き続き、adb.jsファイルからハックしていきたいと思います。

adb.js

ご覧の通り、各OSでの差異はありません。
adb_compare
モジュールは結構ありますね・・・・(^^;;;

スクリーンショット 2014-11-20 21.55.16 スクリーンショット 2014-11-20 21.55.26
スクリーンショット 2014-11-20 21.55.36 スクリーンショット 2014-11-20 21.55.51

予備知識
  1. 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

  2. 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

  3. module

    module 現在のモジュールへの参照です。
    特に module.exports は exports オブジェクトと同じです。
    より詳しくは src/node.js を参照してください。
    module は実際はグローバルではなく、各モジュール毎のローカルです。
    http://d.hatena.ne.jp/jovi0608/20111226/1324879536

  4. 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

  5. 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

モジュール構成

上記予備知識をもとにハックしていきます!

  1. createTCPSocket()
  2. const ADB

1.createTCPSocket()
・Services.jsmをインポートします。
・scriptloaderで、TCPSocket.jsをロードします。
上記の処理を行った上で、TCPSocketスコープを返します。
2.const ADB
ADBオブジェクトを定数として定義します。
このオブジェクト内には下記1~24のモジュール群が
内包されています。

  1. get didRunInitially():初回実行用getterプロパティ
  2. set didRunInitially(newVal):初回実行用setterプロパティ
  3. get ready():待機用getterプロパティ
  4. set ready(newVal):待機用setterプロパティ
  5. init: function adb_init()  OSの種類を判定して、各OSのADB情報を取得します。
  6. start: function adb_start()
     コメントには、このように記載されています。
     We startup by launching adb in server mode, and setting
     the tcp socket preference to |true|

     【訳文】
     サーバー・モードにadbを送り出しtcpソケット優先権を
     セットすることによって処理を開始します。

     関数内で下記処理を実行しています。
    1. onSuccessfulStart
       [処理]-----------------------------------------------
       notifyObserversを使って、adb-ready状態を取得します
       成功した際に、adb-ready状態をbindしています。
    2. function(isAdbRunning)
       [処理]-----------------------------------------------
       requireを使って、「adb-running-checker」を読み込み
       adbが実行されているかを確認します

       adbが実行されていた場合、待機状態でなので
       上記onSuccessfulStartを返します

       adbが実行されていない場合、letにて@mozilla.org/process/utilの
       ローカルスコープprocessを定義します。

       ローカルスコープprocessを初期化します。
       パラメータは、「start-server」です。
       ローカルスコープprocessとadbを同期実行させます。
       ⇒成功した場合、上記onSuccessfulStartを返します。
       ⇒失敗した場合は、rejectします。
  7. stop: function(sync)
     コメントには、このように記載されています。
     Stop the ADB server, but only if we started it.
     If it was started before us, we return immediately.

     【訳文】
     ADB serverの停止をします。
     しかし、自分が実行した場合のみ
     既に実行中の場合は、処理を抜けます。

     [処理]-----------------------------------------------
     didRunInitiallyプロパティを取得します。
     ⇒取得成功した場合は、ADB serverの停止をします。
     ⇒取得失敗した場合は、処理を抜けます。
  8. kill: function adb_kill(aSync)
     コメントには、このように記載されています。
     Kill the ADB server.
     We do this by running ADB again,
     passing it the "kill-server" argument.

     【訳文】
     ADB serverのプロセスを殺して下さい。
     ADB serverのプロセスを再び実行する事で
     kill-serverの前提になります。

     [処理]-----------------------------------------------
     ローカルスコープprocessを定義します。

     ローカルスコープprocessを初期化します。
     パラメータは、「kill-server」です。
     ローカルスコープprocessとadbを同期実行させます。
     ⇒同期成功した場合、adb kill-serverを実行し、
      didRunInitiallyプロパティを返します。
     ⇒同期失敗した場合は、下記の通りです。
      ローカルスコープprocessにて、同期します。
      ⇒同期成功した場合、adb kill-serverを実行し、
       didRunInitiallyプロパティを返します。
      ⇒同期失敗した場合は、下記の通りです。
       コメントには、このように記載されています。
       It's hard to say whether or not ADB is ready at this point,
       but it seems safer to assume that it isn't,
       so code that wants to use it later will try to restart it.

       【訳文】
       ADBがこの時点で準備ができているかどうか言うのは難しい、
       しかし、それがそうではないと仮定することはより安全に見えます、
       したがって、使用したいコードを後に再開しようとするでしょう。

       Services.obs.notifyObserversに
       パラメータ「adb-killed」をセットします。
       didRunInitiallyプロパティを返します。
  9. _isAdbRunning: function()
     [処理]-----------------------------------------------
     OSの判定を行います。
     ①Windowsの場合:tasklist.exeを利用してプロセスリストを取得します。
     ②Windows以外の場合:psを利用してプロセスリストを取得します。
     ③subprocess.jsm よりプロセスコールを利用して、
      Deferredオブジェクトをresolved状態にします。
      非同期deferred.promiseオブジェクトを返します。
  10. _connect: function adb_connect()
     [処理]-----------------------------------------------
     createTCPSocket()メソッドでTCPSocketオブジェクトを定義し
     ローカルホスト:"127.0.0.1", 5037でソケットオープンします。
     socketオブジェクトを返します。
  11. _createRequest: function adb_createRequest(aCommand)
     [処理]-----------------------------------------------
     ①パラメータ:aCommandを大文字にします。
     ②パラメータ:aCommandをエンコードした結果を返します。
  12. _checkResponse: function adb_checkResponse(aPacket, expected)
     コメントには、このように記載されています。
     Checks if the response is expected.
     【訳文】
     レスポンスが想定通りかをチェックします。

     [処理]-----------------------------------------------
     ①パラメータ:aPacketを変数:buffer格納します
     ②変数:bufferをUint32配列:viewへ代入します。
     ③Uint32配列:view[0]を返します。
  13. _unpackPacket: function adb_unpackPacket(aPacket, aIgnoreResponse)
     [処理]-----------------------------------------------
     ①パラメータ:aPacketを変数:buffer格納します
     ②変数:bufferをUint8配列:lengthViewへ代入します。
     ③デコードされたlengthViewの長さを取得します
     ④デコードされた結果を返します。
  14. trackDevices: function adb_trackDevices()
     [処理]-----------------------------------------------
     処理①:ソケット接続処理
     処理②:ソケットエラー処理
     処理③:ソケット切断処理
     処理④:送受信処理
     上記処理を用いてソケットオブジェクトを返します。
  15. listDevices: function adb_listDevices()
     [処理]-----------------------------------------------
     コマンドを利用して、ホストに接続されている
     デバイスのリストを返します。
  16. forwardPort: function adb_forwardPort(aLocalPort, aDevicePort)
     [処理]-----------------------------------------------
     コマンドを利用して、ホストに接続されている
     デバイスのポートを返します。
  17. checkFileMode: function adb_checkFileMode(aMode, aWhat)
     コメントには、このように記載されています。
     Checks a file mode.
     aWhat is one the strings "S_ISDIR" "S_ISCHR" "S_ISBLK"
     "S_ISREG" "S_ISFIFO" "S_ISLNK" "S_ISSOCK"

     【訳文】
     file モードのチェックです。
     aWhatは1つの文字列です。
     「S_ISDIR」「S_ISCHR」「S_ISBLK」
     「S_ISREG」「S_ISFIFO」「S_ISLNK」「S_ISSOCK」

     [処理]-----------------------------------------------
     ①File typesの定数を定義します。
     ②masksを定義します。
     ③masks含まれていなければ、falseを返します。
     ④masks含まれていた時、パラメータ:aModeを返します。
  18. pull: function adb_pull(aFrom, aDest)
     コメントには、このように記載されています。
     pulls a file from the device.
     send "host:transport-any" why??
     if !OKAY, return
     send "sync:"
     if !OKAY, return
     send STAT + hex4(path.length) + path
     recv STAT + 12 bytes (3 x 32 bits: mode, size, time)
     send RECV + hex4(path.length) + path
     while(needs data):
      recv DATA + hex4 + data
     recv DONE + hex4(0)
     send QUIT + hex4(0)
     【訳文】
     デバイスからファイルを送ります。
     "host:transport-any"が送信した時
     正常終了以外なら
     STAT + hex4(path.length) + pathを送信
     STAT + 12 bytes (3 x 32 bits: mode, size, time)を受信
     RECV + hex4(path.length) + pathを送信
     必要なデータ長を受信し終わるまで待機
     DONE + hex4(0)を受信
     QUIT + hex4(0)を送信

     [処理]-----------------------------------------------
     ・各種定義します。
      promise.defer(),socket,state,fileSize,fileData,remaining,
      currentPos,chunkSize,pkgData,headerArray,
      currentHeaderLength,TextEncoder(),
      view,infoLengthPacket
     処理①:shutdown
      [処理]-----------------------------------------------
      ソケットを閉じて、promise.deferオブジェクトをrejectします。
     処理②:extractChunkDataHeader
      コメントには、このように記載されています。
     
      extract chunk data header info. to headerArray.
     

      【訳文】
      extract chunk dataのヘッダ情報

      [処理]-----------------------------------------------
      通信データのヘッダ部を配列に格納します
     処理③:checkChunkDataHeader
      コメントには、このように記載されています。
        chunk data header is 8 bytes length,
      the first 4 bytes: hex4("DATA"), and
      the second 4 bytes: hex4(chunk size)
     

      【訳文】
      chunk data headerは、8バイトの長さです。
      最初の4バイトはhexのデータです。
      次の4バイトは、chunk sizeを格納しています。

      [処理]-----------------------------------------------
      通信データを配列に格納します
  19. hexdump: function adb_hexdump(aArray)
     コメントには、このように記載されています。
     Dump the first few bytes of the given array to the console.
     【訳文】
     Dumpの先頭数バイトはコンソール用の配列です。

     [処理]-----------------------------------------------
     パラメータ:aArrayをデコードします。
     文字列を格納した後、コンソールに出力します。
  20. sockSend: function adb_sockSend(aSocket, aArray)
     コメントには、このように記載されています。
     debugging version of tcpsocket.send()
     【訳文】
     tcpsocket.send()のバージョンデバッグ用です。

     [処理]-----------------------------------------------
     ①パラメータ:aArrayをDumpします。
     ②パラメータ:aSocketを用いて送信します。
  21. push: function adb_push(aFrom, aDest)
     コメントには、このように記載されています。
     pushes a file to the device.
     aFrom and aDest are full paths.
     XXX we should STAT the remote path before sending.

     【訳文】
     デバイスへファイルを送信します。
     パラメータaFrom と aDestはフルパスです。
     リモートパス送信前にSTATをすべきです。

     [処理]-----------------------------------------------
     ・各種定義をします
      promise.defer(),socket,state,
    fileSize,fileData,remaining
    currentPos,fileTime
     処理①:shutdown
      ソケットを閉じて、promise.deferオブジェクトをrejectします。
     処理②:runFSM
    各送信ステータスで処理を分ける
      ステータス:"start"
       ⇒runFSM()を実行します
      ステータス:"send-transport":
       ⇒ADB._createRequest()の転送リクエスト送信をします
      ステータス:"wait-transport":
       ⇒ADB._checkResponse()の応答でNGの時
        shutdown()を実行します。
      ステータス:"send-sync":
       ⇒ADB._createRequest()の同期リクエスト送信をします
      ステータス:"wait-sync":
       ⇒ADB.__checkResponse()の同期待機リクエスト送信をします
      ステータス:"send-send":
       ⇒転送処理を行います。
      ステータス:"wait-done":
       ⇒ADB._checkResponse()の応答でNGの時
        shutdown()を実行します。
      ステータス:"end":
       ⇒ソケットを閉じ、同期処理deferred.resolveを終了します
  22. shell: function adb_shell(aCommand)
     [処理]-----------------------------------------------
    各送信ステータスで処理を分ける
      ステータス:"start":
       ⇒runFSM()を実行します
      ステータス:"send-transport":
       ⇒ADB._createRequest()の転送リクエスト送信をします
      ステータス:"wait-transport":
       ⇒ADB._checkResponse()の応答でNGの時
        shutdown()を実行します。
      ステータス:"send-shell":
       ⇒ADB._createRequest()のshellリクエスト送信をします
      ステータス:"rec-shell":
       ⇒ADB._checkResponse()の応答でNGの時
        shutdown()を実行します。
      ステータス:"decode-shell":
       ⇒shellの応答データをdecodeします。

     処理①:ソケット接続処理
     処理②:ソケットエラー処理
     処理③:ソケット切断処理
     処理④:送受信処理
     上記処理を用いてdeferred.promiseオブジェクトを返します。
  23. root: function adb_root()
     [処理]-----------------------------------------------
    各送信ステータスで処理を分ける
      ステータス:"start":
       ⇒runFSM()を実行します
      ステータス:"send-transport":
       ⇒ADB._createRequest()の転送リクエスト送信をします
      ステータス:"wait-transport":
       ⇒ADB._checkResponse()の応答でNGの時
        shutdown()を実行します。
      ステータス:"send-root":
       ⇒ADB._createRequest()のrootリクエスト送信をします
      ステータス:"rec-root":
       ⇒処理なし

     処理①:ソケット接続処理
     処理②:ソケットエラー処理
     処理③:ソケット切断処理
     処理④:送受信処理
     上記処理を用いてdeferred.promiseオブジェクトを返します。
  24. runCommand: function adb_runCommand(aCommand)
     [処理]-----------------------------------------------
     ・promise.defer()を定義をします

     処理①:ソケット接続処理
     処理②:ソケットエラー処理
     処理③:ソケット切断処理
     処理④:送受信処理
     上記処理を用いてdeferred.promiseオブジェクトを返します

今回のまとめ

今回はadb-client.jsも掲載しようかと考えていましたが、
adb.jsの内容やボリュームの大きさで一つだけになりました

次回はadb-client.jsファイルの中身をハックしていきたいと思います。
お暇な方、宜しかったら見て下さい。m(__)m
グンマー@坊主五厘

追伸
何か間違いが有った場合は、ご指摘ください。