6
Pipeline Build hiddenjar
cmd_build adalah mesin utama cli/hiddenjar. Satu pemanggilan hiddenjar build menjalankan urutan tetap: menyiapkan tool, memilih device, membaca level API, menyusun daftar jar dari $BOOTCLASSPATH, mem-pull dan mengonversi tiap jar, merakit jar akhir di memori, memverifikasinya, lalu memasangnya bila diminta. Skrip berjalan dengan set -euo pipefail, sehingga satu die menghentikan seluruh pipeline cli/hiddenjar:10-10. Bentuk urutan ini berasal dari sketsa pipeline di catatan analisis docs/EMULATOR_CUSTOM_JAR_ANALYSIS.md:192-2031.
Peta tahap dan interaksinya
Diagram berikut menelusuri satu pemanggilan cmd_build dari pemeriksaan prasyarat sampai install_jar, termasuk loop per jar boot classpath.
sequenceDiagram
autonumber
participant B as cmd_build
participant A as adb
participant S as SDK platforms
participant D as d2j-dex2jar.sh
participant J as BuildJar
participant V as verify_compile
B->>B: resolve_adb, ensure_dex_tools, have javac/jar/unzip
B->>A: pick_serial lewat adb devices
A-->>B: emulator-5554
B->>A: getprop ro.build.version.sdk
A-->>B: 37
B->>S: resolve_platform_dir
S-->>B: platforms/android-37.0/android.jar
B->>A: shell 'echo $BOOTCLASSPATH'
A-->>B: daftar jar boot classpath
loop setiap dev_path
B->>A: pull dev_path
alt pull gagal
B->>B: failed++
else jar punya classes*.dex
B->>D: --force -o classes/NAME-classes.jar
D-->>B: converted++
else stripped atau tanpa DEX
B->>B: skipped++
end
end
B->>J: --base android.jar --out android-API-custom.jar
J-->>B: exit 0
B->>V: verify_compile output base_jar
V-->>B: empat pemeriksaan
B->>S: install_jar bila --install
%% fig: Urutan tahap cmd_build
%% desc: cmd_build menyiapkan tool, memilih device, mengonversi tiap jar boot classpath, lalu merakit dan memverifikasi jar sebelum install.Ringkasan tiap tahap, fungsi yang menjalankannya, dan pesan kegagalannya:
| # | Tahap | Fungsi atau perintah | Pesan die |
|---|---|---|---|
| 1 | Prasyarat | resolve_adb, ensure_dex_tools, have javac, have jar, have unzip | adb not found (looked in ...), javac not found (install a JDK), unzip is required |
| 2 | Pilih device | pick_serial lalu boot_avd_if_needed | AVD did not come online, no adb device online — start an emulator or pass --avd NAME |
| 3 | Level API | adb shell getprop ro.build.version.sdk | could not read API level from device |
| 4 | Base jar SDK | resolve_platform_dir | install it via sdkmanager "platforms;android-<api>" or pass --sdk-dir |
| 5 | Daftar jar | echo $BOOTCLASSPATH atau --only-framework | — |
| 6 | Pull, validasi, konversi | adb pull, unzip -l, d2j-dex2jar.sh | no framework jars had usable DEX — use an API >= 34 image or a device |
| 7 | Assemble | assemble_jar lalu BuildJar | Java tools (ASM/Stubifier/ClosureVerify/BuildJar) unavailable — keep cli/*.java intact, assembly failed (see above) |
| 8 | Verifikasi | verify_compile | verification failed (see checks above) |
| 9 | Install | install_jar, hanya dengan --install | — |
Baris 1 sampai 5 ada di kepala cmd_build cli/hiddenjar:241-246, cli/hiddenjar:251-253, cli/hiddenjar:256-264, dan cli/hiddenjar:275-283; baris 6 sampai 9 ada di ekor fungsi yang sama cli/hiddenjar:312-313, cli/hiddenjar:227-236, cli/hiddenjar:337-338, dan cli/hiddenjar:340-343.
Prasyarat: adb, dex-tools, dan JDK
cmd_build memanggil resolve_adb dan ensure_dex_tools, lalu memeriksa javac, jar, dan unzip cli/hiddenjar:241-246. resolve_adb memilih ${sdk}/platform-tools/adb lebih dulu, baru adb di PATH cli/hiddenjar:118-123. ensure_dex_tools memakai --dex-tools DIR bila diberikan, lalu cache ${HOME}/.cache/hiddenjar; bila keduanya kosong ia mengunduh dex-tools 2.4.37, mengekstraknya, mencari d2j-dex2jar.sh, dan memberi bit eksekusi pada skrip di direktorinya cli/hiddenjar:141-162. Versi serta URL unduhan dipatok di konstanta DEX_TOOLS_VERSION dan DEX_TOOLS_URL cli/hiddenjar:15-19.
Pemeriksaan lingkungan yang sama bisa dijalankan lebih dulu lewat hiddenjar doctor, yang mencetak adb, javac, jar, unzip, dex2jar, sdk-dir, dan daftar device cli/hiddenjar:476-491. Opsi baris perintah untuk tiap tahap dijelaskan di Panduan CLI hiddenjar.
Memilih device atau menyalakan AVD
pick_serial mengembalikan --serial bila diberikan. Bila tidak, ia memanggil boot_avd_if_needed, lalu memilih emulator pertama, atau device pertama, dan berhenti dengan no adb device online — start an emulator or pass --avd NAME cli/hiddenjar:193-203. boot_avd_if_needed menjalankan binary emulator dengan -avd "$OPT_AVD" -no-window -no-audio -no-boot-anim -no-snapshot di latar belakang, lalu menunggu dalam dua tahap cli/hiddenjar:169-191.
| Penantian | Kondisi berhenti | Batas |
|---|---|---|
| Device muncul | list_devices tidak kosong | 60 iterasi sleep 2 |
| Boot selesai | getprop sys.boot_completed bernilai 1 | 90 iterasi sleep 2 |
Kedua batas itu ada di loop yang sama, dan wait-for-device dipanggil di antaranya cli/hiddenjar:176-190. Bila device tetap tidak muncul, die "AVD did not come online" menghentikan pipeline cli/hiddenjar:176-190.
Level API dan base jar SDK
Level API diambil dari --api, atau dari getprop ro.build.version.sdk pada device terpilih cli/hiddenjar:251-253. resolve_platform_dir lalu mencari direktori platform: ${sdk}/platforms/android-<api>, ${sdk}/platforms/android-<api>.0, kemudian glob android-<api>* yang source.properties-nya memuat AndroidVersion.ApiLevel=<api> cli/hiddenjar:127-139. Bila tidak ada yang cocok, pipeline mencetak daftar platform terpasang lalu berhenti dengan saran install it via sdkmanager "platforms;android-<api>" or pass --sdk-dir cli/hiddenjar:256-264. Path android.jar dari direktori itu menjadi base untuk perakitan.
Menyusun daftar jar dari $BOOTCLASSPATH
Daftar jar ditentukan oleh --only-framework atau mode default. --only-framework memakai satu entri, /system/framework/framework.jar; mode default menjalankan adb shell 'echo $BOOTCLASSPATH', memecah hasilnya pada :, dan membuang baris kosong cli/hiddenjar:275-283. Jumlah entri yang dipertimbangkan dicatat lewat log Boot classpath entries to consider: ... cli/hiddenjar:275-283. Pada emulator API 37 terukur 52 entri, dan android.net.wifi.WifiManager yang tampak sebagai stub di SDK justru hidup di /apex/com.android.wifi/javalib/framework-wifi.jar docs/EMULATOR_CUSTOM_JAR_ANALYSIS.md:31-352.
⚠️
--only-frameworksengaja tidak lengkap: API mainline seperti Wi-Fi, Bluetooth, connectivity, dan media berada di jar APEX, bukan diframework.jar, sehingga nama-nama itu tidak ikut ter-overlay cli/hiddenjar:277-281.
Pull, validasi, dan konversi per jar
Untuk setiap entri, loop menurunkan nama lokal dengan membuang / di awal dan mengganti / menjadi _, mem-pull ke ${WORK_DIR}/pulled, lalu memvalidasi isi jar cli/hiddenjar:291-307. Validasi memakai dua ukuran: wc -c untuk ukuran berkas dan unzip -l | grep -cE 'classes[0-9]*\.dex' untuk jumlah DEX cli/hiddenjar:299-306. Jar yang lolos dikonversi dengan d2j-dex2jar.sh --force -o ${classes}/<nama>-classes.jar cli/hiddenjar:302-307.
graph TD
PULL["adb pull dev_path"] --> PULLOK{"pull exit 0?"}
PULLOK -->|"tidak"| FAIL["failed++ pull failed"]
PULLOK -->|"ya"| SIZE{"size >= 1024?"}
SIZE -->|"tidak"| SKIP["skipped++ stripped/no DEX"]
SIZE -->|"ya"| DEXCHK{"classes[0-9]*.dex ada?"}
DEXCHK -->|"tidak"| SKIP
DEXCHK -->|"ya"| CONV["d2j-dex2jar.sh --force -o out_jar"]
CONV -->|"exit 0 dan out_jar ada"| OK["converted++"]
CONV -->|"exit != 0"| FAIL2["failed++ dex2jar failed"]
style PULL fill:#f59e0b,color:#000
style PULLOK fill:#f59e0b,color:#000
style SIZE fill:#f59e0b,color:#000
style DEXCHK fill:#f59e0b,color:#000
style CONV fill:#8b5cf6,color:#fff
style OK fill:#2d7d46,color:#fff
style SKIP fill:#dc2626,color:#fff
style FAIL fill:#dc2626,color:#fff
style FAIL2 fill:#dc2626,color:#fff
%% fig: Siklus satu jar boot classpath
%% desc: Setiap jar di-pull lalu divalidasi; jar tanpa DEX dilewati, sisanya dikonversi dex2jar dan dihitung sebagai converted atau failed.Ambang dan akibatnya:
| Pemeriksaan | Ambang | Akibat |
|---|---|---|
| Ukuran jar | kurang dari MIN_JAR_BYTES, yaitu 1024 byte | log skip (stripped/no DEX, <size>B), skipped++ |
| Isi DEX | hasil grep -cE 'classes[0-9]*\.dex' sama dengan 0 | log skip, skipped++ |
| Konversi | d2j-dex2jar.sh exit 0 dan out_jar ada | log converted (<n> dex), converted++ |
| Total | converted lebih besar dari 0 | bila 0, pipeline berhenti |
Batas ukuran 1024 byte datang dari konstanta MIN_JAR_BYTES dengan komentar bahwa jar di bawahnya hampir pasti shell yang sudah di-strip cli/hiddenjar:15-19. Pemeriksaan unzip -l yang sama juga dipakai resep manual sebagai sanity check sebelum konversi docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:98-1133.
Setelah loop, skrip mencetak Jars converted: <n>, skipped: <n>, failed: <n> dan berhenti dengan no framework jars had usable DEX — use an API >= 34 image or a device bila tidak ada satu pun jar yang berhasil dikonversi cli/hiddenjar:312-313. Angka terukur menjelaskan mengapa kasus ini nyata: pada emulator API 24 framework.jar hanya 318 byte, sedangkan pada emulator API 37 berkas yang sama 48.699.241 byte dengan 5 DEX docs/EMULATOR_CUSTOM_JAR_ANALYSIS.md:22-264. Konversi jar API 37 menghasilkan 36.590 kelas, 6.295 di antaranya di bawah com/android/internal/ docs/EMULATOR_CUSTOM_JAR_ANALYSIS.md:87-945.
Assemble jar akhir di memori
Sebelum merakit, ensure_java_tools mengompilasi Stubifier.java, ClosureVerify.java, dan BuildJar.java dengan classpath ASM dari $(dirname "$D2J")/lib, lalu men-cache hasilnya di JAVA_TOOLS_OUT cli/hiddenjar:210-222. Daftar overlay diambil dari glob ${classes}/*-classes.jar, dan output default adalah $(pwd)/android-<api>-custom.jar cli/hiddenjar:324-331. assemble_jar memanggil BuildJar --base <base> --out <out> dengan flag opsional --keep-bodies dan --keep-dangling, lalu die "assembly failed (see above)" bila proses Java keluar non-zero cli/hiddenjar:227-236. Detail filter namespace, prune, dan stubify ada di Perakitan Jar: BuildJar dan Stubifier.
⚠️
--keep-bodiessengaja mempertahankan method body asli, dan skrip sendiri memperingatkan bahwa Gradle lint serta unit test (MockableJarTransform) akan gagal pada jar hasilnya cli/hiddenjar:325-325.
Verifikasi sebagai gerbang akhir
Setelah perakitan, cmd_build mencatat ukuran, jumlah kelas, dan jumlah entri com/android/internal/, lalu memanggil verify_compile dan berhenti dengan verification failed (see checks above) bila gerbang itu tidak lolos cli/hiddenjar:332-338. Empat pemeriksaan yang dijalankan verify_compile dirinci di Verifikasi Jar Kustom, termasuk alasan probe tunggal tidak lagi dipakai docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:177-1796.
Install dan pembersihan work dir
--install memanggil install_jar, yang menyalin android.jar ke android.jar.orig hanya bila backup belum ada, menyalin jar hasil build ke path target, lalu mencetak pengingat hiddenjar restore --api <level> cli/hiddenjar:444-457. Pemanggilan itu terjadi setelah verifikasi lolos cli/hiddenjar:340-343. Langkah pemasangan dan pemulihan SDK dibahas di Memasang Custom android.jar ke SDK.
Work dir berasal dari --work-dir atau mktemp -d "${TMPDIR:-/tmp}/hiddenjar.XXXXXX" cli/hiddenjar:266-273. Trap cleanup menghapus work dir sementara saat keluar kecuali --keep diberikan, dan mencetak Work dir kept at: ... bila direktori dipertahankan cli/hiddenjar:58-65.
Paritas PowerShell
cli/hiddenjar.ps1 mengulang urutan yang sama di Invoke-Build: Resolve-Adb dan Ensure-DexTools, pemeriksaan javac dan jar, Pick-Serial, pembacaan ro.build.version.sdk, dan Resolve-PlatformDir cli/hiddenjar.ps1:183-1967. Bagian pull dan konversinya juga identik: $BOOTCLASSPATH dipecah pada :, tiap jar divalidasi dengan ukuran dan jar tf, lalu $D2J --force -o dijalankan dan kegagalan total memakai pesan no framework jars had usable DEX cli/hiddenjar.ps1:219-2448.
Tiga aturan yang dipegang kedua implementasi: validasi isi jar wajib setelah pull, cache dex-tools di ~/.cache/hiddenjar/, dan gerbang sukses berupa kompilasi probe bukan sekadar repack yang selesai docs/EMULATOR_CUSTOM_JAR_ANALYSIS.md:224-2369. Batas runtime setelah jar terpasang dibahas di Batasan Runtime dan Cakupan Hidden API.