Skip to content

Commit 7583877

Browse files
committed
feat: fingerprint hub, Samsung AVD overlay, firmware XSG, H.264, docs
- Add /api/fingerprint hub (revisions, revert, compare, extended JSON, consistency) - AVD: medium_phone + config.ini Samsung sync on create/start/fingerprint updates - SAMFW: XSG product segment, firmware_package UI + tests - Auto-apply fingerprint + anti-detect after boot; anti_detect CPU/Frida tweaks - Frontend: H.264 hook, touch auto mode, App Store loading, apply messages - README: Recent updates (EN+AR); CHANGELOG Unreleased; Frida scripts Made-with: Cursor
1 parent a3e1dfc commit 7583877

35 files changed

Lines changed: 2569 additions & 176 deletions

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project are documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
12+
- Fingerprint hub (`/api/fingerprint/*`), `extended_json`, revision snapshots / revert / compare, consistency checks on apply.
13+
- Samsung-oriented AVD `config.ini` overlay (`medium_phone` + Samsung manufacturer/LCD); sync on fingerprint updates and on start.
14+
- SAMFW Odin folder merge (e.g. XSG) with product-segment tweak; `backend/tests/test_firmware_xsg.py`.
15+
- Device create: optional `firmware_package`; UI firmware dropdown; default Samsung G996B preset.
16+
- Auto fingerprint + anti-detect apply after emulator boot; anti-detect CPU/characteristics improvements; Frida templates under `scripts/frida/`.
17+
- Optional H.264 WebSocket path (where enabled); touch **auto** mode on device screen; App Store install UX tweaks.
18+
- **README:** “Recent updates (March 2026)” (EN + AR) documenting the above.
19+
820
## [1.0.1] — 2026-03-26
921

1022
### Added

README.md

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
![Docker](https://img.shields.io/badge/Docker-Compose-2496ED?logo=docker&logoColor=white)
1111
![License](https://img.shields.io/badge/license-MIT-green)
1212

13-
Web-based **Android Virtual Device (AVD) farm**: create emulated devices, **unique fingerprints** per instance, start/stop, **live screen** over WebSocket (JPEG), **touch/drag** via ADB, **APK store**, HTTP/SOCKS proxy, **SAMFW** firmware alignment presets, REST API + OpenAPI/Swagger.
13+
Web-based **Android Virtual Device (AVD) farm**: create emulated devices, **unique fingerprints** per instance, start/stop, **live screen** over WebSocket (**JPEG and optional H.264**), **touch/drag** via ADB, **APK store**, HTTP/SOCKS proxy, **SAMFW / Odin folder** firmware alignment, **fingerprint hub API** with revisions, **AVD hardware profile sync** for Samsung vs Pixel, REST API + OpenAPI/Swagger.
1414

1515
**Suggested GitHub “About” description:**
1616
*Android AVD farm — FastAPI + React: live WebSocket mirror, ADB input, per-device fingerprint spoofing, APK store, proxy, Docker, SAMFW presets.*
@@ -26,6 +26,7 @@ Web-based **Android Virtual Device (AVD) farm**: create emulated devices, **uniq
2626
3. [Live stream & control flow](#live-stream--control-flow)
2727
4. [Device lifecycle](#device-lifecycle)
2828
5. [Features (current release)](#features-current-release)
29+
5a. [Recent updates (March 2026)](#recent-updates-march-2026)
2930
6. [Tech stack](#tech-stack)
3031
7. [Quick start](#quick-start)
3132
8. [REST API & WebSocket](#rest-api--websocket)
@@ -157,6 +158,58 @@ stateDiagram-v2
157158
| **Security** | JWT, user/admin roles, device ownership |
158159
| **Docker** | Compose stack with Postgres / Redis / Nginx |
159160
| **CI** | GitHub Actions: backend, frontend, compose validation |
161+
| **H.264 stream** | Optional low-latency screen path over WebSocket (where enabled) |
162+
| **Fingerprint hub** | `/api/fingerprint/*` — revisions, revert, compare, validate, extended JSON |
163+
| **Anti-emulator props** | Layered `setprop` + console + Frida script template; auto-apply after boot |
164+
165+
---
166+
167+
### Recent updates (March 2026)
168+
169+
This release focuses on **Samsung-aligned fingerprints**, **clearer AVD hardware identity**, **firmware package discovery**, and **operator-facing APIs/UI**.
170+
171+
#### Fingerprint system
172+
173+
- **`/api/fingerprint/{device_id}`** (hub): unified REST for full fingerprint documents, optional **`extended`** JSON (extra SIM, sensors, battery, PLMN, etc.), **`revision_label`** on writes.
174+
- **Revisions**: table `fingerprint_revisions` — list, **revert** to a snapshot, **compare** current vs a revision.
175+
- **Apply & randomize** on the hub run **consistency checks** before apply (422 on hard failures).
176+
- **`GET /api/fingerprint/profiles/list`** — device profile silhouettes for editors.
177+
- **Merge path**: `fingerprint_row_to_apply_dict()` merges SQL columns + `extended_json` for the spoofer (legacy `/api/devices/.../fingerprint` uses the same merge).
178+
- **Samsung extended props**: large `ro.product` / `ro.vendor` / CSC map via [`backend/core/fingerprint/samsung_enhanced.py`](backend/core/fingerprint/samsung_enhanced.py); many keys **fail on AVD** (expected — image is AOSP, not One UI). Apply response includes **`note`** and **`detail`** explaining this.
179+
- **Auto-apply on boot**: after a device **starts** successfully, the server runs **fingerprint + anti-detect apply** once (same as manual “Apply”), logged as `fingerprint_auto_apply`.
180+
181+
#### SAMFW / Odin firmware folder names
182+
183+
- **Odin-style directory** names such as `G996BXXSJHZA6_G996BOXMJHZA6_XSG` under [`firmware/`](firmware/) are parsed in [`backend/core/firmware/samfw.py`](backend/core/firmware/samfw.py) (AP, CSC, sales code, locale hints).
184+
- **`merge_firmware_into_fingerprint`** updates `ap_version`, `csc_version`, build fingerprint PDA segment; **XSG** maps fingerprint **product** segment to **`o1sxxx`** (non-EEA style).
185+
- **Tests**: [`backend/tests/test_firmware_xsg.py`](backend/tests/test_firmware_xsg.py).
186+
- **Create device**: optional **`firmware_package`** (ZIP or folder basename) in API; **web UI** loads options from **`GET /api/meta/firmware-packages`**.
187+
188+
#### AVD hardware (Android Studio “Properties”)
189+
190+
- Samsung fingerprints: AVD is created with **`medium_phone`** (SDK has no Samsung device id) then **`~/.android/avd/<name>.avd/config.ini`** is patched: **`hw.device.manufacturer=Samsung`**, **`hw.device.name=medium_phone`**, LCD **1080×2400** / **420** dpi for common **SM-G996B** class devices.
191+
- **Every device start** and **every fingerprint save path** (PUT, randomize, revert on hub + legacy PUT/randomize) calls **`sync_avd_hardware_with_fingerprint`** so the INI stays aligned after edits.
192+
193+
#### Anti-detection
194+
195+
- [`backend/core/fingerprint/anti_detect.py`](backend/core/fingerprint/anti_detect.py): **`ro.build.characteristics`** favours **`default`** for Samsung/qcom; **CPU ABI list** follows fingerprint **`cpu_abi_list_spoof`**; extra flags (`ro.boot.qemu`, virtual device, etc.); Frida template uses dynamic **CPU** placeholders.
196+
- **Random fingerprint IP** in the generator **avoids `10.0.2.x`** (classic emulator guest range) when synthesizing private IPs.
197+
198+
#### Frontend
199+
200+
- **New device** dialog: **firmware package** dropdown; **default preset** Samsung **G996B + Android 15** where applicable.
201+
- **Device screen**: touch mode **Auto** (short movement → tap, longer → swipe) for H.264/JPEG surfaces.
202+
- **Fingerprint editor**: apply result shows **Arabic summary** + expandable **detail** from API.
203+
- **App Store**: install-to-device flow improvements (loading feedback) where implemented.
204+
205+
#### Frida
206+
207+
- Template script and notes: [`scripts/frida/`](scripts/frida/) (optional runtime hooks — does not replace `setprop`).
208+
209+
#### Limitations (unchanged but explicit)
210+
211+
- **Google AVD system image** remains **AOSP / Google APIs** — not a Samsung stock ROM. Deep Samsung-only behavior may still require **physical devices** or **heavy Frida** per app.
212+
- **`tag.display` / Google APIs** in AVD metadata cannot become “Samsung” without a different system image.
160213

161214
---
162215

@@ -366,6 +419,7 @@ CI badge points to **`code-root/emulator-android`**; change it if you fork under
366419
3. [رسم — تدفق البث والتحكم](#رسم--تدفق-البث-والتحكم)
367420
4. [رسم — دورة حياة الجهاز](#رسم--دورة-حياة-الجهاز)
368421
5. [المميزات](#المميزات)
422+
5أ. [التحديثات الأخيرة (مارس 2026)](#التحديثات-الأخيرة-مارس-2026)
369423
6. [المكدس التقني](#المكدس-التقني)
370424
7. [التشغيل السريع](#التشغيل-السريع)
371425
8. [API و WebSocket](#api-و-websocket)
@@ -388,7 +442,7 @@ CI badge points to **`code-root/emulator-android`**; change it if you fork under
388442
- تسجيل الدخول و**JWT**.
389443
- **أجهزة** في قاعدة البيانات لكل مالك؛ **بصمة** و**بروكسي** اختياري.
390444
- **Start** يشغّل **emulator (AVD)** أو يربط **ADB serial**.
391-
- **بث الشاشة:** اشتراك WebSocket (`subscribe_screenshots``adb screencap` مع قفل لكل جهاز، JPEG، Base64 مع أبعاد الجهاز لتحويل إحداثيات اللمس.
445+
- **بث الشاشة:** اشتراك WebSocket (`subscribe_screenshots``adb screencap` مع قفل لكل جهاز، **JPEG واختياري H.264**، Base64 مع أبعاد الجهاز لتحويل إحداثيات اللمس.
392446
- **لمس وسحب:** `tap` / `swipe` عبر WebSocket؛ **طابور تحكم** يُفرغ قبل اللقطة التالية؛ **دمج مقاطع السحب المتسلسلة** في `swipe` واحد عند الإمكان.
393447
- **مستودع APK:** رفع وتثبيت عبر ADB، بما في ذلك **split APKs** (`install-multiple`).
394448

@@ -497,6 +551,57 @@ stateDiagram-v2
497551
| **أمان** | JWT، أدوار، امتلاك الأجهزة |
498552
| **Docker** | Compose كامل |
499553
| **CI** | GitHub Actions |
554+
| **بث H.264** | مسار فيديو اختياري عبر WebSocket عند التفعيل |
555+
| **Fingerprint hub** | `GET/PUT /api/fingerprint/...`، إصدارات، رجوع، مقارنة، JSON موسّع |
556+
| **إخفاء محاكي** | طبقات setprop + كونسول + قالب Frida؛ تطبيق تلقائي بعد الإقلاع |
557+
558+
---
559+
560+
### التحديثات الأخيرة (مارس 2026)
561+
562+
ملخص بالعربية لنفس التغييرات التقنية في [Recent updates (March 2026)](#recent-updates-march-2026) أعلاه.
563+
564+
#### البصمة وواجهات API
565+
566+
- **`/api/fingerprint/{device_id}`**: جلب وتحديث كامل، حقل **`extended`** (JSON) لبيانات إضافية (شريحة ثانية، حساسات، بطارية، شبكة، …)، و**`revision_label`** عند الحفظ.
567+
- **جدول `fingerprint_revisions`**: حفظ نسخ؛ **استرجاع** نسخة سابقة؛ **مقارنة** الحالي مع نسخة.
568+
- **تطبيق وعشوائية** عبر الـ hub تشغّل **فحوصات تناسق** قبل التطبيق (خطأ 422 عند فشل جاد).
569+
- **`GET /api/fingerprint/profiles/list`**: قائمة ملفات أجهزة للمحرر.
570+
- **دمج للتطبيق**: `fingerprint_row_to_apply_dict` يدمج أعمدة SQL مع `extended_json` لمسار الـ spoofer (ومسارات `/api/devices/.../fingerprint` القديمة).
571+
- **سامسونج موسّع**: عشرات `ro.product` / `ro.vendor` / CSC عبر [`samsung_enhanced.py`](backend/core/fingerprint/samsung_enhanced.py) — على AVD يُرفض جزء كبير **وهذا متوقع** (الصورة AOSP وليست One UI). الاستجابة تتضمن **`note`** و **`detail`** لشرح ذلك.
572+
- **بعد تشغيل الجهاز**: يُنفَّذ **تطبيق البصمة + anti-detect** تلقائياً مرة واحدة، مع تسجيل `fingerprint_auto_apply`.
573+
574+
#### فريموير SAMFW / مجلد Odin
575+
576+
- أسماء مثل **`G996BXXSJHZA6_G996BOXMJHZA6_XSG`** تحت [`firmware/`](firmware/) تُحلّل في [`samfw.py`](backend/core/firmware/samfw.py) (AP، CSC، كود مبيعات، لغة/بلد).
577+
- **دمج البصمة** يحدّث `ap_version` / `csc_version` ومقطع الـ PDA في `build_fingerprint`؛ لـ **XSG** يُضبط مقطع المنتج إلى **`o1sxxx`**.
578+
- **اختبارات**: [`backend/tests/test_firmware_xsg.py`](backend/tests/test_firmware_xsg.py).
579+
- **إنشاء جهاز**: الحقل **`firmware_package`** في الـ API؛ الواجهة تعرض قائمة من **`GET /api/meta/firmware-packages`**.
580+
581+
#### ملف AVD (خصائص المحاكي في Android Studio)
582+
583+
- لبصمة **Samsung**: إنشاء AVD بملف **`medium_phone`** ثم تعديل **`config.ini`**: **`hw.device.manufacturer=Samsung`**, **`hw.device.name=medium_phone`**, شاشة تقريبية **1080×2400** و**420** dpi لموديلات مثل **SM-G996B**.
584+
- عند **كل تشغيل** وعند **كل تحديث للبصمة** (PUT، عشوائي، revert على الـ hub والمسار القديم) يُستدعى **`sync_avd_hardware_with_fingerprint`** لتحديث الـ INI.
585+
586+
#### مكافحة كشف المحاكي
587+
588+
- [`anti_detect.py`](backend/core/fingerprint/anti_detect.py): **`ro.build.characteristics`** مناسب لسامسونج؛ **ABI** من **`cpu_abi_list_spoof`**؛ أعلام إضافية؛ قالب Frida يستخدم قيم CPU من البصمة.
589+
- توليد **IP عشوائي** في البصمة **يتجنب `10.0.2.x`**.
590+
591+
#### الواجهة الأمامية
592+
593+
- إنشاء جهاز: قائمة **حزمة فريموير**؛ **افتراضي preset** سامسونج G996B + Android 15 حيث ينطبق.
594+
- شاشة الجهاز: وضع لمس **تلقائي** (لمسة قصيرة = نقرة، حركة أوضح = سحب).
595+
- محرر البصمة: بعد Apply تظهر **ملخص عربي** + **تفصيل** من الـ API.
596+
597+
#### Frida
598+
599+
- قوالب في [`scripts/frida/`](scripts/frida/) — اختياري، لا يغني عن `setprop`.
600+
601+
#### حدود واضحة
602+
603+
- صورة نظام المحاكي تبقى **Google APIs / AOSP** وليست روم Samsung كاملاً.
604+
- **`tag.display` = Google APIs** لا يتغير بدون تغيير صورة النظام.
500605

501606
---
502607

backend/api/routes/devices.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,18 @@ async def _create_avd_background(device_id: int, avd_name: str, api_level: int,
268268
async with AsyncSessionLocal() as db:
269269
try:
270270
avd = emulator_manager.avd_backend
271-
success = await avd.create_avd(avd_name, api_level=api_level, arch=arch)
271+
fp_row = await db.execute(
272+
select(DeviceFingerprint).where(DeviceFingerprint.device_id == device_id)
273+
)
274+
fp = fp_row.scalar_one_or_none()
275+
success = await avd.create_avd(
276+
avd_name,
277+
api_level=api_level,
278+
arch=arch,
279+
manufacturer=fp.manufacturer if fp else None,
280+
brand=fp.brand if fp else None,
281+
device_model=fp.device_model if fp else None,
282+
)
272283
result = await db.execute(select(Device).where(Device.id == device_id))
273284
device = result.scalar_one_or_none()
274285
if device:
@@ -324,6 +335,7 @@ async def start_device(
324335
raise HTTPException(status_code=400, detail="Device is already running")
325336

326337
device.status = DeviceStatus.booting
338+
device.adb_serial = None
327339
await db.flush()
328340
await db.refresh(device)
329341
await ws_manager.broadcast(device_id, {"type": "status", "status": "booting", "device_id": device_id})
@@ -335,26 +347,76 @@ async def start_device(
335347

336348
async def _start_device_background(device_id: int):
337349
from db.database import AsyncSessionLocal
350+
from core.fingerprint.spoofer import FingerprintSpoofer
351+
from core.fingerprint.merge import fingerprint_row_to_apply_dict
352+
from core.fingerprint.samsung_enhanced import merge_profile_defaults_for_apply
353+
338354
async with AsyncSessionLocal() as db:
339355
try:
340356
result = await db.execute(select(Device).where(Device.id == device_id))
341357
device = result.scalar_one_or_none()
342358
if not device:
343359
return
360+
owner_id = device.owner_id
344361
success, info = await emulator_manager.start(device)
362+
adb_serial = None
363+
console_port = None
345364
if success:
346365
device.status = DeviceStatus.running
347366
device.pid = info.get("pid")
348367
device.adb_port = info.get("adb_port")
349368
device.adb_serial = info.get("adb_serial")
350369
device.console_port = info.get("console_port")
370+
adb_serial = device.adb_serial
371+
console_port = device.console_port
351372
else:
352373
device.status = DeviceStatus.error
353374
await db.commit()
354375
await ws_manager.broadcast(
355376
device_id,
356377
{"type": "status", "status": device.status.value, "device_id": device_id, "adb_serial": device.adb_serial}
357378
)
379+
380+
# بعد الإقلاع: تطبيق البصمة + طبقة إخفاء المحاكي تلقائياً (يتطلب adb root كالمعتاد)
381+
if success and adb_serial:
382+
fp_row = await db.execute(
383+
select(DeviceFingerprint).where(DeviceFingerprint.device_id == device_id)
384+
)
385+
fp = fp_row.scalar_one_or_none()
386+
if fp:
387+
try:
388+
raw = fingerprint_row_to_apply_dict(
389+
fp, {"console_port": console_port}
390+
)
391+
raw.pop("_extended_raw", None)
392+
merged = merge_profile_defaults_for_apply(raw)
393+
spoofer = FingerprintSpoofer()
394+
adb_tool = ADBTool()
395+
report = await spoofer.apply(adb_tool, adb_serial, merged)
396+
n_ok, n_fail = len(report.get("applied", [])), len(report.get("failed", []))
397+
await _log_operation(
398+
db,
399+
device_id,
400+
owner_id,
401+
"fingerprint_auto_apply",
402+
OperationStatus.success,
403+
f"applied={n_ok} failed={n_fail}",
404+
)
405+
await db.commit()
406+
except Exception as ex:
407+
logger.warning("fingerprint_auto_apply device=%s: %s", device_id, ex)
408+
try:
409+
await _log_operation(
410+
db,
411+
device_id,
412+
owner_id,
413+
"fingerprint_auto_apply",
414+
OperationStatus.failure,
415+
str(ex)[:500],
416+
)
417+
await db.commit()
418+
except Exception:
419+
pass
358420
except Exception as e:
359421
logger.error(f"Start device {device_id} failed: {e}")
360422
async with AsyncSessionLocal() as db2:
@@ -382,6 +444,7 @@ async def stop_device(
382444

383445
device.status = DeviceStatus.stopped
384446
device.pid = None
447+
device.adb_serial = None
385448
await db.flush()
386449
await db.refresh(device)
387450
await ws_manager.broadcast(device_id, {"type": "status", "status": "stopped", "device_id": device_id})
@@ -405,6 +468,7 @@ async def restart_device(
405468

406469
device.status = DeviceStatus.booting
407470
device.pid = None
471+
device.adb_serial = None
408472
await db.flush()
409473
await db.refresh(device)
410474
background_tasks.add_task(_start_device_background, device_id)
@@ -445,6 +509,12 @@ async def get_screenshot(
445509
png_bytes = await adb_tool.screenshot(device.adb_serial)
446510
return Response(content=png_bytes, media_type="image/png")
447511
except Exception as e:
512+
err = str(e).lower()
513+
if "not found" in err and ("device" in err or "adb:" in err):
514+
raise HTTPException(
515+
status_code=503,
516+
detail="ADB device not connected — emulator may have stopped or serial is stale.",
517+
)
448518
raise HTTPException(status_code=500, detail=f"Screenshot failed: {e}")
449519

450520

0 commit comments

Comments
 (0)