adb vốn được làm cho cáp USB, rồi sau đó là mạng nội bộ. Nó cũng chạy được qua Internet, và rất nhiều đội phụ thuộc vào điều đó: một CI runner ở khu vực này nói chuyện với điện thoại ở khu vực khác, một lập trình viên ở nhà truy cập dàn máy ở văn phòng, một bộ test điều khiển điện thoại đám mây. Tuy vậy, cấu hình mặc định giả định mạng đáng tin cậy. Cấu hình sai, cầu nối gỡ lỗi trở thành remote shell cho bất kỳ ai tìm ra nó.
Bài hướng dẫn này giải thích adb giao tiếp ra sao, bốn cách an toàn để kéo nó qua Internet kèm lệnh cụ thể, và một checklist để giữ nó luôn đóng.
adb giao tiếp thế nào
Có ba thành phần. adb client là lệnh bạn gõ. adb server là một tiến trình chạy nền trên cùng máy, lắng nghe ở 127.0.0.1:5037 và theo dõi các thiết bị. adbd là daemon trên điện thoại. Server nói chuyện với adbd qua USB, qua TCP thuần sau lệnh adb tcpip, hoặc qua TLS với gỡ lỗi không dây trên Android 11 trở lên.
Làm từ xa nghĩa là kéo một trong các chặng đó qua Internet: client tới server, hoặc server tới adbd. Bạn kéo chặng nào sẽ quyết định phương pháp.
Hai sự thật định hình bức tranh bảo mật. adbd yêu cầu người dùng cho phép khóa RSA của từng máy tính một lần, nhờ đó chặn được người lạ mà điện thoại chưa từng thấy. Nhưng chế độ TCP cổ điển không mã hóa gì cả: kết quả shell, logcat và mọi tệp bạn push đều đi dưới dạng văn bản rõ.
Những điều không bao giờ làm
Đừng forward cổng 5555 hay 5037 ra Internet trên router, và đừng mở chúng trong firewall của cloud. Năm 2018, một con sâu tên ADB.Miner lây lan qua các thiết bị Android để lộ adb ở cổng 5555, phần lớn là TV box, và biến chúng thành máy đào tiền mã hóa. Các trình quét liên tục tìm cổng adb đang mở.
Cũng tránh khởi động adb server với -a, cờ này khiến nó lắng nghe trên mọi interface. Ai chạm tới được cổng đó sẽ điều khiển mọi thiết bị gắn vào host, không có hộp thoại xác nhận khóa nào cả.
Cách 1: SSH tunnel tới adb server ở xa
Dùng cách này khi điện thoại cắm USB vào một host bạn SSH vào được: giá máy ở văn phòng, máy trong lab, máy chạy CI. Forward một cổng local tới adb server của host và trỏ client vào đó:
ssh -N -L 15037:127.0.0.1:5037 user@lab-host adb -P 15037 devices ADB_SERVER_SOCKET=tcp:127.0.0.1:15037 adb -s SERIAL logcat -d
Dùng cổng local khác 5037, để adb server của chính bạn không đụng với tunnel. Cài đặt, push, shell và logcat đều chạy, vì client truyền mọi thứ qua kết nối của nó tới server.
Một điểm bất ngờ: adb forward giờ mở cổng trên host trong lab, không phải trên laptop của bạn. Muốn truy cập cổng đã forward từ máy mình, thêm một -L thứ hai cho cổng đó vào lệnh SSH.
SSH cho bạn khóa và mã hóa mà bạn vốn đã tin, và một tunnel phủ được cả một kệ máy. Cái giá là phải vận hành một host và có tài khoản trên đó, và ai có tài khoản ấy sẽ điều khiển được mọi điện thoại đang gắn vào.
Cách 2: SSH tunnel tới adbd
Dùng cách này khi điện thoại nằm trong một mạng bạn vào được qua jump host, nhưng bạn không có máy nào ở đó cắm USB được. Đưa điện thoại vào chế độ TCP một lần, qua USB hoặc gỡ lỗi không dây, rồi mở tunnel tới nó:
adb tcpip 5555 ssh -N -L 15555:192.168.1.50:5555 user@jump-host adb connect 127.0.0.1:15555
Chọn cổng local nằm ngoài khoảng 5555 đến 5585, vì adb server coi các cổng local trong khoảng đó là emulator. Điện thoại phải ở yên chế độ TCP, mà phần lớn bản build bỏ chế độ này sau khi khởi động lại, và lần kết nối đầu vẫn hiện hộp thoại xác nhận khóa trên máy, nên phải có người bấm chấp nhận một lần.
Cách 3: Gỡ lỗi không dây qua VPN
Android 11 bổ sung gỡ lỗi không dây: ghép đôi bằng mã, sau đó kết nối qua TLS. Tính năng này được thiết kế cho mạng nội bộ, nhưng vẫn chạy qua VPN như WireGuard hay Tailscale, miễn là laptop và điện thoại tới được địa chỉ private của nhau. Bật Gỡ lỗi không dây trong Tùy chọn cho nhà phát triển, chọn ghép đôi bằng mã ghép đôi, rồi chạy:
adb pair 100.64.0.12:37099 adb connect 100.64.0.12:41235
adb pair hỏi mã sáu chữ số. Cổng ghép đôi và cổng kết nối khác nhau, và cả hai đều đổi mỗi lần bật tắt gỡ lỗi không dây. Tính năng tìm thiết bị qua mDNS không đi qua được hầu hết VPN, nên hãy gõ địa chỉ hiển thị trên điện thoại. Thiết lập này cũng tự tắt khi điện thoại rời mạng Wi-Fi của nó, nên không hợp với việc gì cần chạy không người trông.
Cách 4: Relay của device cloud
Các device cloud đặt một relay phía trước adbd và cấp cho mỗi điện thoại một địa chỉ riêng. Chi tiết khác nhau tùy nhà cung cấp. Đây là cách relay hoạt động trên Clousd, theo tài liệu ADB:
- ADB tắt theo mặc định. Bạn bật nó cho từng máy, với danh sách cho phép tối đa 20 địa chỉ IP hoặc dải.
- Quyền truy cập tự hết hạn: mặc định sau 24 giờ, tối đa 7 ngày. Phiên không hoạt động tự đóng sau 30 phút.
- Bạn đăng nhập bằng mã dùng một lần, chỉ hiển thị một lần. Nhập sai mã thì phiên bị đóng, sai nhiều lần thì relay tự tắt.
- Root, remount, reverse, reboot và các lệnh tương tự luôn bị từ chối, và mọi phiên đều được ghi nhật ký.
adb connect HOST:PORT adb -s HOST:PORT shell clousd-login CODE adb -s HOST:PORT install app-debug.apk adb -s HOST:PORT logcat -d
Không có gì phải tự host, cũng không cần mở gì trên mạng của bạn. Cái giá là vài lệnh bị loại khỏi cuộc chơi. Những quy trình dựa vào adb reverse, chẳng hạn app React Native gọi tới Metro server trên laptop của bạn, cần một đường khác, ví dụ một dev server mà điện thoại tới được bằng URL. Nếu ngay từ đầu bạn không có phần cứng để kết nối, một điện thoại Android từ xa trên đám mây đã có sẵn relay phía trước.
So sánh bốn cách
| SSH tới adb server | SSH tới adbd | Gỡ lỗi không dây qua VPN | Relay của device cloud | |
|---|---|---|---|---|
| Điện thoại ở đâu | cắm USB vào host bạn quản lý | trong mạng phía sau jump host | trong mạng mà VPN của bạn tới được | trong data center của nhà cung cấp |
| Bạn phải duy trì | host và quyền SSH | jump host và chế độ TCP | VPN, điện thoại luôn trên Wi-Fi | không gì cả |
| Kiểm soát truy cập | khóa SSH | khóa SSH cộng khóa adb | VPN cộng ghép đôi | danh sách cho phép, hạn dùng, mã một lần |
| Còn sau khi điện thoại khởi động lại | có | thường là không | không | có |
adb reverse | có | có | có | thường bị từ chối |
| Phù hợp cho | giá máy văn phòng, host CI | truy cập lab một lần | điện thoại cá nhân | đội nhóm và CI không có phần cứng |
Độ trễ và băng thông
adb nói nhiều nhưng chịu được khoảng cách. adb shell tương tác vẫn dùng tốt ở độ trễ khứ hồi 200 ms, và logcat stream ổn. Cài đặt và push phụ thuộc vào tốc độ upload của bạn, nên một APK 150 MB qua đường upload chậm ở nhà sẽ mất vài phút.
Instrumentation test chịu thiệt nhiều nhất, vì mỗi thao tác UI đều chờ phản hồi. Hãy tăng timeout và thay các lệnh sleep cố định bằng việc chờ điều kiện, thay vì kéo dài sleep. Để mirror màn hình bằng scrcpy qua SSH tunnel, giảm bitrate và kích thước bằng scrcpy --video-bit-rate=2M --max-size=1024. Với điện thoại đám mây, màn hình trên trình duyệt thường làm luôn việc đó.
Test thiết bị Android từ xa trong CI
Một job CI test trên điện thoại từ xa có bốn bước: kết nối, chờ thiết bị, chạy, ngắt kết nối. Thêm bước đăng nhập nếu relay của bạn có.
adb connect "$DEVICE" adb -s "$DEVICE" wait-for-device adb -s "$DEVICE" install -r app-debug.apk adb -s "$DEVICE" install -r app-debug-androidTest.apk adb -s "$DEVICE" shell am instrument -w com.example.app.test/androidx.test.runner.AndroidJUnitRunner adb disconnect "$DEVICE"
Giữ địa chỉ thiết bị và mã đăng nhập trong secret của CI, không để trong repository. Trang kiểm thử ứng dụng cho thấy cùng lần chạy đó qua REST API trông thế nào, còn test ứng dụng Android online đi sâu vào lượt smoke test và các lệnh logcat. Nếu bạn đang cân nhắc có nên giữ giá máy riêng hay không, xem device farm Android.
Checklist bảo mật
- Không bao giờ để lộ cổng 5037 hoặc 5555 ra Internet.
- Coi
~/.android/adbkeynhư một thông tin đăng nhập. Đó là danh tính của bạn với mọi điện thoại từng tin nó, nên đừng chép nó sang máy dùng chung. - Với điện thoại trong lab, thỉnh thoảng dùng Thu hồi ủy quyền gỡ lỗi USB trong Tùy chọn cho nhà phát triển.
- Ưu tiên quyền truy cập tự hết hạn và chỉ giới hạn cho các địa chỉ đã biết.
- Dùng xong thì ngắt kết nối và dừng server bằng
adb disconnectvàadb kill-server, và tắt gỡ lỗi không dây. - Lưu lại ai đã kết nối tới điện thoại nào và khi nào.


