From 4ac9f3474bfcab393389b2b040319acbe7085d31 Mon Sep 17 00:00:00 2001 From: NGB-Was-Taken <76197326+NGB-Was-Taken@users.noreply.github.com> Date: Sat, 25 Jul 2026 18:36:11 +0545 Subject: [PATCH] Fix extension installation with shizuku (#3630) * Fix extension installation with shizuku * Changelog * Move changelog to end --- CHANGELOG.md | 1 + .../mihon/app/shizuku/IShellInterface.aidl | 2 +- .../extension/installer/ShizukuInstaller.kt | 11 ++++- .../java/mihon/app/shizuku/ShellInterface.kt | 44 ++----------------- 4 files changed, 15 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36c295b5c..6c1c0c6b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co ### Fixed - Fixed app bars remaining visible after changing pages by tapping in the paged reader after using the chapter navigator slider ([@AntsyLich](https://github.com/AntsyLich)) ([#3567](https://github.com/mihonapp/mihon/pull/3567)) - Fixed MangaBaka User Agent string ([@MajorTanya](https://github.com/MajorTanya)) ([#3578](https://github.com/mihonapp/mihon/pull/3578)) +- Fixed extension installation with shizuku installer ([@NGB-Was-Taken](https://github.com/NGB-Was-Taken)) ([#3630](https://github.com/mihonapp/mihon/pull/3630)) ## [v0.20.1] - 2026-07-09 ### Added diff --git a/app/src/main/aidl/mihon/app/shizuku/IShellInterface.aidl b/app/src/main/aidl/mihon/app/shizuku/IShellInterface.aidl index 3f56b52d2..1e8dfd8f0 100644 --- a/app/src/main/aidl/mihon/app/shizuku/IShellInterface.aidl +++ b/app/src/main/aidl/mihon/app/shizuku/IShellInterface.aidl @@ -1,7 +1,7 @@ package mihon.app.shizuku; interface IShellInterface { - void install(in AssetFileDescriptor apk) = 1; + void install(in AssetFileDescriptor apk, in IntentSender intentSender) = 1; void destroy() = 16777114; } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt index 8f3eecf74..cd2670746 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.extension.installer +import android.app.PendingIntent import android.app.Service import android.content.BroadcastReceiver import android.content.ComponentName @@ -39,6 +40,7 @@ class ShizukuInstaller(private val service: Service) : Installer(service) { .processNameSuffix("shizuku_service") .debuggable(BuildConfig.DEBUG) .daemon(false) + .version(2) } private val connection = object : ServiceConnection { @@ -53,6 +55,13 @@ class ShizukuInstaller(private val service: Service) : Installer(service) { } } + private val statusIntent = PendingIntent.getBroadcast( + service.applicationContext, + 0, + Intent(ACTION_INSTALL_RESULT).setPackage(BuildConfig.APPLICATION_ID), + PendingIntent.FLAG_MUTABLE, + ) + private val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, Int.MIN_VALUE) @@ -110,7 +119,7 @@ class ShizukuInstaller(private val service: Service) : Installer(service) { super.processEntry(entry) try { service.contentResolver.openAssetFileDescriptor(entry.uri, "r").use { - shellInterface?.install(it) + shellInterface?.install(it, statusIntent.intentSender) } service.contentResolver.delete(entry.uri, null, null) } catch (e: Exception) { diff --git a/app/src/main/java/mihon/app/shizuku/ShellInterface.kt b/app/src/main/java/mihon/app/shizuku/ShellInterface.kt index 216f82b30..cc8618164 100644 --- a/app/src/main/java/mihon/app/shizuku/ShellInterface.kt +++ b/app/src/main/java/mihon/app/shizuku/ShellInterface.kt @@ -40,9 +40,6 @@ package mihon.app.shizuku import android.annotation.SuppressLint -import android.app.PendingIntent -import android.content.Context -import android.content.Intent import android.content.IntentSender import android.content.pm.PackageInstaller import android.content.res.AssetFileDescriptor @@ -51,21 +48,18 @@ import android.os.IBinder import android.os.ParcelFileDescriptor import android.os.UserHandle import eu.kanade.tachiyomi.BuildConfig -import eu.kanade.tachiyomi.extension.installer.ACTION_INSTALL_RESULT import rikka.shizuku.SystemServiceHelper import java.io.OutputStream import kotlin.system.exitProcess class ShellInterface : IShellInterface.Stub() { - - private val context = createContext() private val userId = UserHandle::class.java .getMethod("myUserId") .invoke(null) as Int private val packageName = BuildConfig.APPLICATION_ID @SuppressLint("PrivateApi") - override fun install(apk: AssetFileDescriptor) { + override fun install(apk: AssetFileDescriptor, intentSender: IntentSender) { val pmInterface = Class.forName($$"android.content.pm.IPackageManager$Stub") .getMethod("asInterface", IBinder::class.java) .invoke(null, SystemServiceHelper.getSystemService("package")) @@ -136,50 +130,18 @@ class ShellInterface : IShellInterface.Stub() { apk.createInputStream().use { input -> input.copyTo(output) } } - val statusIntent = PendingIntent.getBroadcast( - context, - 0, - Intent(ACTION_INSTALL_RESULT).setPackage(packageName), - PendingIntent.FLAG_MUTABLE, - ) - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { session::class.java.getMethod("commit", IntentSender::class.java, Boolean::class.java) - .invoke(session, statusIntent.intentSender, false) + .invoke(session, intentSender, false) } else { session::class.java.getMethod("commit", IntentSender::class.java) - .invoke(session, statusIntent.intentSender) + .invoke(session, intentSender) } } override fun destroy() { exitProcess(0) } - - @SuppressLint("PrivateApi") - private fun createContext(): Context { - val activityThread = Class.forName("android.app.ActivityThread") - val systemMain = activityThread.getMethod("systemMain").invoke(null) - val systemContext = activityThread.getMethod("getSystemContext").invoke(systemMain) as Context - - val shellUserHandle = UserHandle::class.java - .getConstructor(Int::class.java) - .newInstance(userId) - - val shellContext = systemContext::class.java.getMethod( - "createPackageContextAsUser", - String::class.java, - Int::class.java, - UserHandle::class.java, - ).invoke( - systemContext, - "com.android.shell", - Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY, - shellUserHandle, - ) as Context - - return shellContext.createPackageContext("com.android.shell", 0) - } } // Constant hidden from the SDK