325 lines
10 KiB
Bash
Executable File
325 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
||
# ================================================================
|
||
# 一键恢复脚本 — 5种控制模式全部打通
|
||
# 用法: bash connect_all.sh
|
||
#
|
||
# 执行前提: 设备已完成 USB 调试授权(设备屏幕点击"允许")
|
||
# ================================================================
|
||
|
||
set -e
|
||
|
||
SDK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
APP_DIR="$SDK_DIR/app"
|
||
SERVER_URL="http://127.0.0.1:8899"
|
||
WS_URL="ws://127.0.0.1:8899/ws/device"
|
||
AGENT_APK="$SDK_DIR/android-app/app/build/outputs/apk/debug/app-debug.apk"
|
||
FRIDA_SERVER="/data/local/tmp/frida-server"
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
ok() { echo -e "${GREEN}✅ $1${NC}"; }
|
||
warn() { echo -e "${YELLOW}⚠️ $1${NC}"; }
|
||
fail() { echo -e "${RED}❌ $1${NC}"; }
|
||
info() { echo -e "${BLUE}ℹ️ $1${NC}"; }
|
||
|
||
PASS=0
|
||
FAIL=0
|
||
WARN=0
|
||
|
||
# ================================================================
|
||
# 0. 前置检查
|
||
# ================================================================
|
||
|
||
echo ""
|
||
echo "=========================================="
|
||
echo " 机擎 SDK — 五通道一键恢复"
|
||
echo "=========================================="
|
||
echo ""
|
||
|
||
# 检查 ADB
|
||
if ! command -v adb &>/dev/null; then
|
||
fail "ADB 未安装"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查设备
|
||
DEVICE_STATUS=$(adb devices | grep -v "List" | grep -v "^$" | head -1)
|
||
if [ -z "$DEVICE_STATUS" ]; then
|
||
fail "未检测到设备,请连接 USB"
|
||
exit 1
|
||
fi
|
||
|
||
SERIAL=$(echo "$DEVICE_STATUS" | awk '{print $1}')
|
||
STATUS=$(echo "$DEVICE_STATUS" | awk '{print $2}')
|
||
|
||
if [ "$STATUS" = "unauthorized" ]; then
|
||
fail "设备 $SERIAL 未授权"
|
||
echo ""
|
||
echo " 请在设备屏幕上:"
|
||
echo " 1. 找到「允许USB调试」对话框"
|
||
echo " 2. 勾选「始终允许此计算机」"
|
||
echo " 3. 点击「确定」"
|
||
echo ""
|
||
echo " 授权后重新运行此脚本"
|
||
exit 1
|
||
fi
|
||
|
||
if [ "$STATUS" != "device" ]; then
|
||
fail "设备状态异常: $STATUS"
|
||
exit 1
|
||
fi
|
||
|
||
ok "ADB 已连接: $SERIAL ($STATUS)"
|
||
PASS=$((PASS+1))
|
||
|
||
# 获取设备信息
|
||
MODEL=$(adb -s "$SERIAL" shell getprop ro.product.model 2>/dev/null | tr -d '\r')
|
||
ANDROID=$(adb -s "$SERIAL" shell getprop ro.build.version.release 2>/dev/null | tr -d '\r')
|
||
ANDROID_ID=$(adb -s "$SERIAL" shell settings get secure android_id 2>/dev/null | tr -d '\r')
|
||
DEVICE_ID=$(echo -n "$ANDROID_ID" | md5 -q 2>/dev/null || echo -n "$ANDROID_ID" | md5sum | awk '{print $1}')
|
||
|
||
echo " 设备: $MODEL | Android $ANDROID"
|
||
echo " 设备ID: $DEVICE_ID"
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 1. 检查/启动 SDK 服务器
|
||
# ================================================================
|
||
|
||
info "检查 SDK 服务器..."
|
||
|
||
HEALTH=$(curl -s --connect-timeout 3 "$SERVER_URL/health" 2>/dev/null || echo "")
|
||
if echo "$HEALTH" | grep -q '"healthy"'; then
|
||
ok "SDK 服务器运行中"
|
||
PASS=$((PASS+1))
|
||
else
|
||
warn "SDK 服务器未运行,正在启动..."
|
||
lsof -ti :8899 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||
sleep 2
|
||
cd "$APP_DIR"
|
||
nohup python3 -m uvicorn main:app --host 0.0.0.0 --port 8899 --reload > /tmp/sdk_server.log 2>&1 &
|
||
sleep 5
|
||
HEALTH=$(curl -s --connect-timeout 5 "$SERVER_URL/health" 2>/dev/null || echo "")
|
||
if echo "$HEALTH" | grep -q '"healthy"'; then
|
||
ok "SDK 服务器已启动"
|
||
PASS=$((PASS+1))
|
||
else
|
||
fail "SDK 服务器启动失败,查看 /tmp/sdk_server.log"
|
||
FAIL=$((FAIL+1))
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 2. ADB 反向代理(让设备 127.0.0.1:8899 指向 Mac)
|
||
# ================================================================
|
||
|
||
info "设置 ADB 反向代理..."
|
||
|
||
adb -s "$SERIAL" reverse tcp:8899 tcp:8899 2>/dev/null
|
||
if [ $? -eq 0 ]; then
|
||
ok "ADB reverse 已设置 (设备 127.0.0.1:8899 → Mac)"
|
||
PASS=$((PASS+1))
|
||
else
|
||
fail "ADB reverse 设置失败"
|
||
FAIL=$((FAIL+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 3. 通道一:ADB 静默控制验证
|
||
# ================================================================
|
||
|
||
info "验证 ADB 静默控制..."
|
||
|
||
ADB_SCREENSHOT=$(adb -s "$SERIAL" shell screencap -p /sdcard/test_connect.png 2>&1)
|
||
if [ $? -eq 0 ]; then
|
||
ok "ADB 控制可用 (截图成功)"
|
||
adb -s "$SERIAL" shell rm -f /sdcard/test_connect.png 2>/dev/null
|
||
PASS=$((PASS+1))
|
||
else
|
||
fail "ADB 控制失败: $ADB_SCREENSHOT"
|
||
FAIL=$((FAIL+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 4. 通道二:Agent WebSocket 验证
|
||
# ================================================================
|
||
|
||
info "验证 Agent WebSocket..."
|
||
|
||
AGENT_INSTALLED=$(adb -s "$SERIAL" shell pm list packages 2>/dev/null | grep "com.workphone.agent" || echo "")
|
||
if [ -z "$AGENT_INSTALLED" ]; then
|
||
warn "Agent App 未安装"
|
||
if [ -f "$AGENT_APK" ]; then
|
||
info "正在安装 Agent App..."
|
||
adb -s "$SERIAL" install -r -g "$AGENT_APK" 2>/dev/null
|
||
if [ $? -eq 0 ]; then
|
||
ok "Agent App 安装成功"
|
||
else
|
||
fail "Agent App 安装失败"
|
||
FAIL=$((FAIL+1))
|
||
fi
|
||
else
|
||
warn "APK 不存在: $AGENT_APK,跳过安装"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
else
|
||
ok "Agent App 已安装"
|
||
fi
|
||
|
||
# 启动 Agent App
|
||
adb -s "$SERIAL" shell am start -n com.workphone.agent/.MainActivity 2>/dev/null
|
||
sleep 3
|
||
|
||
# 检查 WebSocket 连接
|
||
HEALTH2=$(curl -s --connect-timeout 3 "$SERVER_URL/health" 2>/dev/null || echo "")
|
||
WS_ONLINE=$(echo "$HEALTH2" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('devices_online',0))" 2>/dev/null || echo "0")
|
||
if [ "$WS_ONLINE" -gt 0 ] 2>/dev/null; then
|
||
ok "Agent WebSocket 在线 (设备数: $WS_ONLINE)"
|
||
PASS=$((PASS+1))
|
||
else
|
||
warn "Agent WebSocket 未连接 (可能需要在App中手动连接)"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 5. 通道三:Hook / Frida 验证
|
||
# ================================================================
|
||
|
||
info "验证 Hook / Frida..."
|
||
|
||
IS_ROOTED=$(adb -s "$SERIAL" shell "su -c 'id' 2>/dev/null" | tr -d '\r')
|
||
if echo "$IS_ROOTED" | grep -q "uid=0"; then
|
||
ok "Root 权限可用"
|
||
|
||
FRIDA_RUNNING=$(adb -s "$SERIAL" shell "su -c 'ps -ef | grep frida-server | grep -v grep'" 2>/dev/null | tr -d '\r')
|
||
if [ -n "$FRIDA_RUNNING" ]; then
|
||
ok "Frida Server 运行中"
|
||
PASS=$((PASS+1))
|
||
else
|
||
FRIDA_EXISTS=$(adb -s "$SERIAL" shell "su -c 'ls $FRIDA_SERVER'" 2>/dev/null | tr -d '\r')
|
||
if echo "$FRIDA_EXISTS" | grep -q "frida-server"; then
|
||
info "启动 Frida Server..."
|
||
adb -s "$SERIAL" shell "su -c 'chmod 755 $FRIDA_SERVER && $FRIDA_SERVER -D &'" 2>/dev/null &
|
||
sleep 3
|
||
FRIDA_CHECK=$(adb -s "$SERIAL" shell "su -c 'ps -ef | grep frida-server | grep -v grep'" 2>/dev/null)
|
||
if [ -n "$FRIDA_CHECK" ]; then
|
||
ok "Frida Server 已启动"
|
||
PASS=$((PASS+1))
|
||
else
|
||
warn "Frida Server 启动失败(可能需要 Magisk 授权)"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
else
|
||
warn "Frida Server 未部署到设备"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
fi
|
||
else
|
||
warn "Root 权限不可用(需要 Magisk 授权 Shell)"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 6. 通道四:AI Agent 验证
|
||
# ================================================================
|
||
|
||
info "验证 AI Agent..."
|
||
|
||
AI_STATUS=$(curl -s --connect-timeout 3 "$SERVER_URL/api/v3/ai/status" 2>/dev/null || echo "")
|
||
if echo "$AI_STATUS" | grep -q '"available"'; then
|
||
ok "AI 引擎可用"
|
||
PASS=$((PASS+1))
|
||
else
|
||
AI_AVAIL=$(echo "$AI_STATUS" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',{}).get('available',''))" 2>/dev/null || echo "")
|
||
if [ "$AI_AVAIL" = "True" ] || [ "$AI_AVAIL" = "true" ]; then
|
||
ok "AI 引擎可用"
|
||
PASS=$((PASS+1))
|
||
else
|
||
warn "AI 引擎不可用(需配置 DEEPSEEK_API_KEY 或 Ollama)"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 7. 通道五:scrcpy 验证
|
||
# ================================================================
|
||
|
||
info "验证 scrcpy..."
|
||
|
||
if command -v scrcpy &>/dev/null; then
|
||
ok "scrcpy 已安装"
|
||
PASS=$((PASS+1))
|
||
info "可运行: scrcpy -s $SERIAL --max-size 1024"
|
||
else
|
||
warn "scrcpy 未安装 (brew install scrcpy)"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 8. 心跳监控验证
|
||
# ================================================================
|
||
|
||
info "验证 AI 心跳监控..."
|
||
|
||
HB_DASH=$(curl -s --connect-timeout 3 "$SERVER_URL/api/v3/heartbeat/dashboard" 2>/dev/null || echo "")
|
||
if echo "$HB_DASH" | grep -q '"total_devices"'; then
|
||
TOTAL=$(echo "$HB_DASH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',{}).get('total_devices',0))" 2>/dev/null || echo "0")
|
||
AVG=$(echo "$HB_DASH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',{}).get('avg_score',0))" 2>/dev/null || echo "0")
|
||
ok "心跳监控在线 (设备: $TOTAL, 平均健康分: $AVG)"
|
||
PASS=$((PASS+1))
|
||
else
|
||
warn "心跳监控数据暂无(等待首次心跳)"
|
||
WARN=$((WARN+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 9. 注册设备映射
|
||
# ================================================================
|
||
|
||
info "注册设备映射..."
|
||
|
||
REGISTER_RESULT=$(curl -s -X POST --connect-timeout 3 "$SERVER_URL/api/v3/devices/$DEVICE_ID/connection-modes" 2>/dev/null || echo "")
|
||
if [ -n "$REGISTER_RESULT" ]; then
|
||
ok "连接模式已评估"
|
||
PASS=$((PASS+1))
|
||
fi
|
||
echo ""
|
||
|
||
# ================================================================
|
||
# 总结
|
||
# ================================================================
|
||
|
||
echo "=========================================="
|
||
echo " 恢复结果"
|
||
echo "=========================================="
|
||
echo ""
|
||
echo -e " ${GREEN}通过: $PASS${NC}"
|
||
echo -e " ${YELLOW}警告: $WARN${NC}"
|
||
echo -e " ${RED}失败: $FAIL${NC}"
|
||
echo ""
|
||
|
||
if [ $FAIL -eq 0 ]; then
|
||
echo -e "${GREEN}所有关键通道已就绪!${NC}"
|
||
else
|
||
echo -e "${RED}有 $FAIL 个通道需要修复${NC}"
|
||
fi
|
||
|
||
echo ""
|
||
echo " 控制台: $SERVER_URL"
|
||
echo " API文档: $SERVER_URL/docs"
|
||
echo " 设备ID: $DEVICE_ID"
|
||
echo " ADB序列号: $SERIAL"
|
||
echo ""
|