12
Batasan Runtime dan Cakupan Hidden API
Jar kustom yang dihasilkan hiddenjar adalah alat kompilasi, bukan izin akses. Mengganti android.jar di SDK hanya membuat javac mau membaca signature @hide dan com.android.internal.*; perilaku aplikasi saat berjalan di device tidak berubah sama sekali. README menyatakan batas ini secara eksplisit: jar kustom hanya membuka kompilasi, sementara Android 9+ (API 28+) tetap menegakkan blocklist non-SDK untuk aplikasi non-system. README.md:99-1001
Kompilasi Berhasil, Runtime Belum Tentu
Rantai di bawah memisahkan dua gerbang yang sering dianggap satu. Gerbang pertama adalah javac dan bisa dilewati dengan jar kustom. Gerbang kedua adalah ART di device dan tidak bisa dilewati oleh jar mana pun.
graph TD
A["hiddenjar build"] --> B["android.jar kustom"]
B --> C["javac: hidden API resolve"]
C --> D["APK dipasang dan dijalankan"]
D --> E{"API 28+ dan non-system app?"}
E -->|ya| F["blocklist non-SDK menolak akses"]
E -->|tidak| G["akses diizinkan"]
F --> H["NoSuchMethodError / ClassNotFoundException"]
style A fill:#f59e0b,color:#000
style B fill:#8b5cf6,color:#fff
style C fill:#2d7d46,color:#fff
style D fill:#336791,color:#fff
style E fill:#f59e0b,color:#000
style F fill:#dc2626,color:#fff
style G fill:#2d7d46,color:#fff
style H fill:#dc2626,color:#fff
%% fig: Dua gerbang akses hidden API
%% desc: Jar kustom hanya meloloskan gerbang kompilasi; gerbang runtime tetap dijaga blocklist non-SDK pada API 28+.Blocklist Non-SDK Sejak API 28
Dokumentasi batasan menyebut konsekuensi konkretnya: kegagalan tidak muncul saat build, melainkan saat aplikasi berjalan. Ekspektasi yang wajar adalah NoSuchMethodError atau ClassNotFoundException kecuali aplikasi berstatus platform/system app atau API yang dipakai ada di greylist. Jar kustom tidak mengubah apa pun pada runtime. docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:195-1972
⚠️ Verifikasi empat tahap di
cli/hiddenjarmengujijavacdan integritas jar, bukan izin runtime. Jar yang lolos verifikasi tetap bisa gagal di device bila simbol yang dipanggil diblokir.
Kerapuhan Signature Antar Versi
Hidden API tidak dijamin kompatibel. Signature-nya berubah tanpa pemberitahuan, sehingga jar harus dibangun ulang per level API. docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:1983
Pengalaman pemakaian di repository ini mencatat kasus nyata: sejak jar kustom v28, sejumlah method tidak lagi dapat diakses dan Android Studio melaporkan formatShortElapsedTime has private access; workaround-nya adalah menyalin method tersebut ke kode sendiri. sample/src/main/java/com/anggrayudi/hiddenapi/sample/MainActivity.kt:44-524
| Gejala | Penyebab | Tindakan |
|---|---|---|
NoSuchMethodError / ClassNotFoundException saat runtime | blocklist non-SDK pada API 28+ | jangan andalkan akses langsung; bungkus dengan fallback |
formatShortElapsedTime has private access saat kompilasi | signature berubah antar level API | salin method ke kode sendiri |
| Kelas hilang setelah ganti level API | signature hidden berubah tanpa jaminan kompatibilitas | bangun ulang jar per level API |
Kompromi --keep-bodies dan --keep-dangling
Secara default BuildJar menulis ulang setiap body method menjadi throw new RuntimeException("Stub!") dan mencetak peringatan bila mode itu dimatikan: [build] --keep-bodies: real method bodies kept; Gradle lint/unit tests will FAIL on this jar. cli/BuildJar.java:97-1095 Alasannya teknis: body hasil dex2jar membawa blok try/catch, dan MockableJarGenerator milik Gradle — dipakai lint serta unit test — gagal dengan Cannot read field "outgoingEdges" because "handlerRangeBlock" is null (issue #46). Stub dibuat menyerupai android.jar bawaan SDK, dan karena javac hanya membaca signature, symbol hidden tetap resolve. cli/Stubifier.java:26-376
Sisi lain kompromi ini: body asli memang berguna untuk membaca source hasil decompile, tetapi MockableJarTransform akan menolak jar tersebut. docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:199-2067
Prune berjalan dengan logika yang sama. Overlay hanya mengambil tiga namespace, android/, com/android/internal/, dan dalvik/; kelas yang supertype-nya tidak lagi resolve dibuang agar graf jar tertutup seperti android.jar stok. cli/BuildJar.java:47-488 --keep-dangling melewati langkah itu dan mempertahankan kelas yatim, dengan risiko memunculkan kembali error issue #100 bila kelas tersebut dirujuk. docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:207-2109 CLI bahkan menggagalkan build bila jar membawa namespace yang menaungi JDK, bila jumlah kelasnya lebih sedikit dari jar SDK dasar, atau bila ada kelas publik dengan supertype tak terselesaikan. docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:177-17910
| Flag | Efek | Konsekuensi |
|---|---|---|
| (default) | body di-stub, kelas yatim dipangkas | lint dan unit test menerima jar; body asli tidak bisa dibaca |
--keep-bodies | body dex2jar asli dipertahankan | pesan: --keep-bodies: keeping real method bodies; Gradle lint/unit tests (MockableJarTransform) will FAIL on this jar |
--keep-dangling | kelas dengan supertype terfilter tetap ada | graf supertype tidak tertutup; risiko error issue #100 saat dirujuk |
Peringatan kedua flag dicetak ke stderr sebelum perakitan dimulai, sehingga kompromi yang dipilih terlihat di log build. cli/hiddenjar:325-326
Cakupan Sumber: Citra Emulator dan DEX yang Tersisa
Cakupan hidden API bergantung pada bytecode yang benar-benar ada di sumber. hiddenjar menolak jar yang tampak sebagai cangkang kosong: ambang MIN_JAR_BYTES=1024 dipakai bersama pemeriksaan classes[0-9]*\.dex, dan jar yang gagal salah satu syarat dilewati dengan pesan skip (stripped/no DEX, ...). cli/hiddenjar:19-19 cli/hiddenjar:296-301 Bila tidak ada satu pun jar yang punya DEX usable, proses berhenti dengan no framework jars had usable DEX — use an API >= 34 image or a device. cli/hiddenjar:313-313
Angka ukuran berikut menjelaskan mengapa citra lama tidak memadai — DEX-nya sudah dipindahkan ke boot image.
| Sumber | API | Ukuran /system/framework/framework.jar | Isi |
|---|---|---|---|
Emulator google_apis, arm64 | 24 | 318 bytes | kosong, hanya META-INF/MANIFEST.MF |
Emulator google_apis, arm64 | 37 | ≈48 MB | 5 DEX penuh |
| Ponsel fisik (Samsung A52) | 34 | ≈51 MB | penuh |
docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:66-7011
Pada citra API 37, konversi DEX menghasilkan 36.590 kelas, 6.295 di antaranya berada di bawah com/android/internal/. docs/BUILD_CUSTOM_ANDROID_JAR_FROM_EMULATOR.md:12112 Jumlah itu adalah ukuran permukaan yang bisa dikompilasi, bukan ukuran permukaan yang bisa diakses saat runtime.
Untuk kebutuhan resource internal, jalur yang dipakai bukan akses langsung ke com.android.internal.R melainkan resolusi lewat nama, seperti yang dibahas di InternalAccessor: Membaca Resource com.android.internal dan ResourcesHolder dan Pengiriman via Broadcast.