Shizuku

repository·master·Indexed 12 days ago

https://github.com/rikkaapps/shizuku

A tool that allows Android apps to use system APIs with elevated privileges via root or ADB without the overhead of executing shell commands. It acts as a middleman between apps and the Android system server using IPC (Binder). The project includes a server process, the Shizuku API for application integration, and utilities like AdbClient and AdbKey for ADB-based authentication and communication.

Tokens
1.7K
Snippets
4
Records
9
Agent score
97%

What's inside Shizuku

  1. How Shizuku works

    master

    Shizuku provides a way to use system APIs with higher permissions by acting as a middleman between an app and the Android system server.

    Instead of running slow and unreliable shell commands (like pm enable/disable) via su, Shizuku runs a server process with root or ADB privileges. When an app starts, it receives a binder to the Shizuku server. The app can then send requests to Shizuku, which forwards them to the system server via IPC (Binder), and returns the results. To the app, using these elevated system APIs is almost identical to using standard system APIs directly.

  2. Important limitations when using Shizuku

    master

    When developing with Shizuku, be aware of these constraints:

    1. ADB Permission Limits: ADB permissions are restricted and vary by Android version. Always verify permissions using ShizukuService.
    2. Hidden API Restrictions: Since Android 9, access to hidden APIs is restricted for normal apps. You may need tools like AndroidHiddenApiBypass to access them.
    3. Android 8.0 (API 26) ADB Limitations: On API 26, ADB lacks permission to use registerUidObserver. If your process is not started by an Activity, it is recommended to trigger the binder delivery by starting a transparent activity.
    4. Direct transactRemote usage: If you use transactRemote directly instead of ShizukuBinderWrapper, be aware that AIDL forms and transaction codes (e.g., IPackageManager$Stub.TRANSACTION_...) can change between Android versions. Using ShizukuBinderWrapper is the recommended way to avoid these issues.
  3. Build the Shizuku server

    master

    To build the Shizuku server for development, follow these steps:

    1. Clone the repository with submodules:
    git clone --recurse-submodules
    1. Run the Gradle task to assemble the manager:
    ./gradlew :manager:assembleDebug

    Note: The :manager:assembleDebug task generates a debuggable server, allowing you to attach a debugger to shizuku_server. In Android Studio, ensure that "Run/Debug configurations" -> "Always install with package manager" is checked so the server uses your latest code.

  4. Verify Shizuku permissions and environment

    master

    Because ADB permissions are limited and vary across Android versions, you should verify the environment before calling elevated APIs. Use the following methods from ShizukuService:

    • ShizukuService#getUid: Check if Shizuku is running as a user ADB process.
    • ShizukuService#checkPermission: Check if the Shizuku server has sufficient permissions to perform the requested operation.
  5. Use AdbKey for ADB authentication

    master

    The AdbKey class manages the RSA key pair and certificate required for ADB-based authentication in Shizuku. It handles the generation of a 2048-bit RSA key pair, secure storage of the private key using the Android KeyStore (via AES/GCM encryption), and provides the encoded public key format expected by the Android system.

    Key capabilities:

    • Public Key Generation: Provides an adbPublicKey byte array encoded in the specific format required by Android's libcrypto_utils.
    • Signing: The sign(data: ByteArray?) method allows signing data using the managed private key, applying a specific internal padding required for the protocol.
    • SSL/TLS Support: Provides an sslContext configured with a custom X509ExtendedKeyManager and a TrustManager that trusts all certificates, suitable for secure ADB-based communication channels.
    // Example conceptual usage of AdbKey
    val adbKey = AdbKey(adbKeyStore, "my_device_name")
    val publicKeyBytes = adbKey.adbPublicKey
    val signature = adbKey.sign(someData)
    val context = adbKey.sslContext
  6. Implement AdbKeyStore for key persistence

    master

    To use AdbKey, you must provide an implementation of the AdbKeyStore interface. This interface is responsible for persisting the encrypted private key bytes.

    PreferenceAdbKeyStore is a provided implementation that uses Android SharedPreferences to store the key as a Base64 encoded string under the key "adbkey".

    interface AdbKeyStore {
        fun put(bytes: ByteArray)
        fun get(): ByteArray?
    }
    
    // Implementation using SharedPreferences
    class PreferenceAdbKeyStore(private val preference: SharedPreferences) : AdbKeyStore {
        override fun put(bytes: ByteArray) { ... }
        override fun get(): ByteArray? { ... }
    }
  7. Use AdbClient to connect to Shizuku via ADB

    master

    The AdbClient class is used to establish a connection to the Shizuku server using the ADB protocol. It supports both plain TCP and TLS connections (TLS requires Android 9 or higher).

    To use it, you must provide a host, port, and an AdbKey instance which handles authentication (signing and RSA public keys) and provides the sslContext for TLS handshakes.

    Key lifecycle steps:

    1. Instantiate AdbClient(host, port, key).
    2. Call connect() to perform the ADB handshake, including optional TLS upgrading and authentication.
    3. Use shellCommand(command, listener) to execute commands.
    4. Call close() to release the socket and streams.
    // Note: AdbKey implementation is required for authentication
    val client = AdbClient("127.0.0.1", 5555, myAdbKey)
    client.connect()
    
    client.shellCommand("ls /sdcard") { data ->
        val output = String(data)
        println(output)
    }
    
    client.close()
  8. Execute shell commands with AdbClient.shellCommand()

    master

    The shellCommand method allows you to run a command on the remote host via the ADB protocol.

    • command: The string representing the shell command to execute (e.g., "ls" or "pm list packages").
    • listener: An optional callback function that receives ByteArray chunks of the command's output as they are received. This is useful for streaming large outputs.

    The method handles the ADB A_OPEN request and manages the subsequent A_WRTE (data) and A_CLSE (close) messages automatically.

    client.shellCommand("getprop") { data ->
        // Handle chunk of output
        val chunk = String(data)
        println(chunk)
    }