LoginSignup
13
6

More than 3 years have passed since last update.

Docker for Mac でコンテナからホスト側に接続したAndroidデバイスにadbする方法

Last updated at Posted at 2019-07-17

Appium のテストを作っているのだけど、Docker化したくなってやっていたときに結構ハマったのでメモ。

完全に自分用メモ

前提

  • Docker for Macを動かしているOSは Mojave
  • コンテナはalpineベース

前提の前提:ADBの仕組みをざっくり

https://blog.csdn.net/xgbing/article/details/52096880 あたりに説明があるのを絵で書くと、

Slice.png

  • adbはサーバーとクライアントがあって
  • サーバープロセスがUSBドライバを通じて
  • 実機のADBデーモン(adbd)と対話する

みたいなイメージ。

adbクライアントとadbサーバーは別PCでも大丈夫

ポイントとしては、クライアントとサーバー間は単純なTCP通信なので、

Slice.png

adbサーバーが立っているマシンとadbクライアントを操作するマシンは別であってもよい。

  • adbクライアントのlocalhost:5037 -> adbサーバのlocalhost:5037 のポートフォワーディングをする
  • adbの -H オプションを使う

のいずれかの方法でTCP通信ができるようにしてやればよい。
(ちなみに -H オプションは今回のお試しをやるまで私は知らなかった :sweat_smile:

そもそもどーやってadbを入れたらいいのか

alpineにadbコマンドを使えるようにする方法は2つある。

android-toolsパッケージ

https://github.com/sorccu/docker-adb/issues/9 をみると、

apk --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ add android-tools

すればいけるよ!とある。

たしかにこれでいける。いけるんだけど、後述する理由で、採用には至らなかった。

頑張ってダウンロードしてインストールする

最終的にはこれでいけた。理由は後述。

adbをインストール

apk --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ add android-tools でやってみる。

adb devices で何も出ない

そりゃそうだ。コンテナ(alpine linux)には何のデバイスも刺さって&ポートフォワーディングもしていないんだから。

adbクライアントが動いているコンテナから、adbサーバーが動いているホスト(Mac)まで5037のポートフォワードができればいいのだが、Dockerではコンテナ→ホストのポートフォワーディングはできない。さて、どうしたものか・・・(これが今回の話のきっかけだった)

/dev/bus/usb をポート指定すればよい?

--privileged -v /dev/bus/usb:/dev/bus/usb してやれば、コンテナからホストOSのUSBデバイスに直アクセスできるよ♪
https://codeday.me/jp/qa/20190301/305118.html

うん。ホストがLinuxならね。

Docker for Macだと無理だこれ・・・。

adbの -H オプションを使うと良い!

adbクライアントはDockerコンテナ側で動かし、adbサーバーはホスト側のを使う作戦。

$ adb
Android Debug Bridge version 1.0.41
Version 29.0.1-5644136
Installed as /Users/yusuke-iwaki/Library/Android/sdk/platform-tools/adb

global options:
 -a         listen on all network interfaces, not just localhost
 -d         use USB device (error if multiple devices connected)
 -e         use TCP/IP device (error if multiple TCP/IP devices available)
 -s SERIAL  use device with given serial (overrides $ANDROID_SERIAL)
 -t ID      use device with given transport id
 -H         name of adb server host [default=localhost]
 -P         port of adb server [default=5037]
 -L SOCKET  listen on given socket for adb server [default=tcp:localhost:5037]

-H name of adb server host [default=localhost] これだ!

必然的に、Mac側にもAndroid SDKを入れないといけないわけだが、Androidアプリ開発している人なら入っているでしょう(え?w

で、やってみると・・・

/usr/src/app # adb -H docker.for.mac.localhost devices
List of devices attached
adb server version (41) doesn't match this client (40); killing...
ADB server didn't ACK
Full server startup log: /tmp/adb.0.log
Server had pid: 20
--- adb starting (pid 20) ---
adb I 07-17 04:52:43    20    20 main.cpp:56] Android Debug Bridge version 1.0.40
adb I 07-17 04:52:43    20    20 main.cpp:56] Version 9.0.0_r33
adb I 07-17 04:52:43    20    20 main.cpp:56] Installed as /usr/bin/adb
adb I 07-17 04:52:43    20    20 main.cpp:56] 
error: could not install *smartsocket* listener: listening on specified hostname currently unsupported

* failed to start daemon
error: cannot connect to daemon

Ω\ζ°)チーン

TCPレベルでの通信には成功したのだが、
apk --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ add android-tools でインストールされるadbはバージョンが古い!! ので、このままではadbプロトコルでの通信ができない。

adbを入れ直す

https://qiita.com/kichinaga/items/66872432747e76d72af7 を頼りに、愚直にSDKをzipダウンロードしてきてPATHとか通して、ANDROID_HOMEとか設定して、

みたいなことをやる。Dockerfileの断片を書くと

# Android SDK
RUN apk add --no-cache openjdk8-jre wget unzip
RUN wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip && unzip -d /usr/local/android sdk-tools-linux-4333796.zip && rm sdk-tools-linux-4333796.zip
ENV JAVA_HOME /usr/lib/jvm/default-jvm
ENV ANDROID_HOME /usr/local/android
ENV PATH /usr/local/android/tools:/usr/local/android/tools/bin:/usr/local/android/platform-tools:/usr/lib/jvm/default-jvm/bin:$PATH
RUN mkdir -p ~/.android && touch ~/.android/repositories.cfg
RUN yes | sdkmanager --licenses
RUN sdkmanager "tools" "platform-tools"

# add glibc (see: https://hub.docker.com/r/frolvlad/alpine-glibc/dockerfile)
RUN ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" && \
    ALPINE_GLIBC_PACKAGE_VERSION="2.29-r0" && \
    ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    apk add --no-cache --virtual=.build-dependencies wget ca-certificates && \
    echo \
        "-----BEGIN PUBLIC KEY-----\
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu/fW4A25y9m\
        y70AGEa/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\
        tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf/lEXPpFpOPL88LKnDBgbh7wkCp\
        m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ/KfzGtpke1wqws4au0Ab4qPY\
        KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\
        Zvo9GI2e2MaZyo9/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\
        1QIDAQAB\
        -----END PUBLIC KEY-----" | sed 's/   */\n/g' > "/etc/apk/keys/sgerrand.rsa.pub" && \
    wget \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    apk add --no-cache \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    \
    rm "/etc/apk/keys/sgerrand.rsa.pub" && \
    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true && \
    echo "export LANG=$LANG" > /etc/profile.d/locale.sh && \
    \
    apk del glibc-i18n && \
    \
    rm "/root/.wget-hsts" && \
    apk del .build-dependencies && \
    rm \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME"

こんなかんじ。

glibcのところをちゃんとやらないと、

/usr/src/app # adb -H docker.for.mac.localhost devices
/bin/sh: adb: not found
/usr/src/app # which adb
/usr/local/android/platform-tools/adb
/usr/src/app # ldd /usr/local/android/platform-tools/adb
    /lib64/ld-linux-x86-64.so.2 (0x7f8010899000)
    libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7f8010899000)
    libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f8010899000)
    libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f8010899000)
    librt.so.1 => /lib64/ld-linux-x86-64.so.2 (0x7f8010899000)
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7f801063f000)
    libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f8010899000)
Error relocating /usr/local/android/platform-tools/adb: __vfprintf_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __fprintf_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __vsnprintf_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: group_member: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __syslog_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __fdelt_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __snprintf_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __strdup: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __asprintf_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __strcat_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: __vasprintf_chk: symbol not found
Error relocating /usr/local/android/platform-tools/adb: strtoll_l: symbol not found
Error relocating /usr/local/android/platform-tools/adb: strtoull_l: symbol not found

こんな感じで、adbコマンドが有るのに not foundとか言われて、結構ハマることになる。

気を取り直して・・・

そんなわけで、adbを最新のものにしたら

/usr/src/app # adb -H docker.for.mac.localhost devices
List of devices attached
emulator-5554   device

キタ━━━━(゚∀゚)━━━━!!

13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6