From 7f209a71bc36a48421678c6b9baf470079323567 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Mon, 20 Jul 2026 04:08:43 +0500 Subject: [PATCH 1/4] set hidden api exemptions only once --- ackpine-plugins/libsu/build.gradle.kts | 1 - .../ackpine/libsu/RootPackageInstaller.kt | 12 ----- ackpine-plugins/privileged/build.gradle.kts | 1 + .../privileged/src/main/AndroidManifest.xml | 32 +++++++++++++ .../HiddenApiExemptionsInitializer.kt | 48 +++++++++++++++++++ ackpine-plugins/shizuku/build.gradle.kts | 1 - .../shizuku/ShizukuPackageInstaller.kt | 11 ----- docs/guide/libsu.md | 32 +++++++++++++ docs/guide/shizuku.md | 32 +++++++++++++ 9 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 ackpine-plugins/privileged/src/main/AndroidManifest.xml create mode 100644 ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/HiddenApiExemptionsInitializer.kt diff --git a/ackpine-plugins/libsu/build.gradle.kts b/ackpine-plugins/libsu/build.gradle.kts index 5fa2824b4..9c327af63 100644 --- a/ackpine-plugins/libsu/build.gradle.kts +++ b/ackpine-plugins/libsu/build.gradle.kts @@ -46,5 +46,4 @@ dependencies { implementation(projects.ackpineRuntime) implementation(androidx.room.runtime) implementation(libs.libsu.service) - implementation(libs.hiddenApiBypass) } \ No newline at end of file diff --git a/ackpine-plugins/libsu/src/main/kotlin/ru/solrudev/ackpine/libsu/RootPackageInstaller.kt b/ackpine-plugins/libsu/src/main/kotlin/ru/solrudev/ackpine/libsu/RootPackageInstaller.kt index 337194105..ab1bccd75 100644 --- a/ackpine-plugins/libsu/src/main/kotlin/ru/solrudev/ackpine/libsu/RootPackageInstaller.kt +++ b/ackpine-plugins/libsu/src/main/kotlin/ru/solrudev/ackpine/libsu/RootPackageInstaller.kt @@ -19,11 +19,9 @@ package ru.solrudev.ackpine.libsu import android.content.Context import android.content.pm.IPackageInstaller import android.content.pm.IPackageManager -import android.os.Build import android.os.IBinder import android.os.ServiceManager import androidx.annotation.RestrictTo -import org.lsposed.hiddenapibypass.HiddenApiBypass import ru.solrudev.ackpine.plugability.AckpinePlugin import ru.solrudev.ackpine.privileged.PackageInstallerProxy import java.util.UUID @@ -48,16 +46,6 @@ internal class RootPackageInstaller( @JvmSynthetic internal fun create(context: Context): RootPackageInstaller { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - HiddenApiBypass.addHiddenApiExemptions( - "Landroid/content/pm/IPackageManager", - "Landroid/content/pm/IPackageInstaller", - "Landroid/content/pm/IPackageInstallerSession", - "Landroid/content/pm/PackageInstaller", - "Landroid/os/UserHandle", - "Landroid/os/ServiceManager" - ) - } val rootService = RootProxyService.bind(context) val remotePackageManager = IPackageManager.Stub.asInterface( RootProxyBinderWrapper(rootService, ServiceManager.getService("package")) diff --git a/ackpine-plugins/privileged/build.gradle.kts b/ackpine-plugins/privileged/build.gradle.kts index 874328719..c3f202a71 100644 --- a/ackpine-plugins/privileged/build.gradle.kts +++ b/ackpine-plugins/privileged/build.gradle.kts @@ -36,4 +36,5 @@ dependencies { api(projects.ackpineCore) compileOnly(projects.ackpinePlugins.androidStubs) implementation(projects.ackpineRuntime) + implementation(libs.hiddenApiBypass) } \ No newline at end of file diff --git a/ackpine-plugins/privileged/src/main/AndroidManifest.xml b/ackpine-plugins/privileged/src/main/AndroidManifest.xml new file mode 100644 index 000000000..55b3c12dd --- /dev/null +++ b/ackpine-plugins/privileged/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/HiddenApiExemptionsInitializer.kt b/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/HiddenApiExemptionsInitializer.kt new file mode 100644 index 000000000..feae4cef3 --- /dev/null +++ b/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/HiddenApiExemptionsInitializer.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2026 Ilya Fomichev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ru.solrudev.ackpine.privileged + +import android.content.Context +import android.os.Build +import androidx.annotation.RestrictTo +import androidx.startup.Initializer +import org.lsposed.hiddenapibypass.HiddenApiBypass + +/** + * Initializes hidden API exemptions using `androidx.startup`. + */ +@RestrictTo(RestrictTo.Scope.LIBRARY) +internal class HiddenApiExemptionsInitializer : Initializer { + + override fun create(context: Context) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + return + } + HiddenApiBypass.setHiddenApiExemptions( + "Landroid/content/pm/IPackageManager", + "Landroid/content/pm/IPackageInstaller", + "Landroid/content/pm/IPackageInstallerSession", + "Landroid/content/pm/PackageInstaller", + "Landroid/os/UserHandle", + "Landroid/os/ServiceManager" + ) + } + + override fun dependencies(): List>> { + return emptyList() + } +} \ No newline at end of file diff --git a/ackpine-plugins/shizuku/build.gradle.kts b/ackpine-plugins/shizuku/build.gradle.kts index 476ff1a1b..8bdbd3666 100644 --- a/ackpine-plugins/shizuku/build.gradle.kts +++ b/ackpine-plugins/shizuku/build.gradle.kts @@ -46,5 +46,4 @@ dependencies { implementation(projects.ackpineRuntime) implementation(androidx.room.runtime) implementation(libs.shizuku.api) - implementation(libs.hiddenApiBypass) } \ No newline at end of file diff --git a/ackpine-plugins/shizuku/src/main/kotlin/ru/solrudev/ackpine/shizuku/ShizukuPackageInstaller.kt b/ackpine-plugins/shizuku/src/main/kotlin/ru/solrudev/ackpine/shizuku/ShizukuPackageInstaller.kt index a643ebb76..f8e3ff8c4 100644 --- a/ackpine-plugins/shizuku/src/main/kotlin/ru/solrudev/ackpine/shizuku/ShizukuPackageInstaller.kt +++ b/ackpine-plugins/shizuku/src/main/kotlin/ru/solrudev/ackpine/shizuku/ShizukuPackageInstaller.kt @@ -20,10 +20,8 @@ import android.content.Context import android.content.pm.IPackageInstaller import android.content.pm.IPackageManager import android.content.pm.PackageInstaller -import android.os.Build import android.os.IBinder import androidx.annotation.RestrictTo -import org.lsposed.hiddenapibypass.HiddenApiBypass import rikka.shizuku.Shizuku import rikka.shizuku.ShizukuBinderWrapper import rikka.shizuku.SystemServiceHelper @@ -56,15 +54,6 @@ internal class ShizukuPackageInstaller( @JvmSynthetic internal fun create(context: Context): ShizukuPackageInstaller { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - HiddenApiBypass.addHiddenApiExemptions( - "Landroid/content/pm/IPackageManager", - "Landroid/content/pm/IPackageInstaller", - "Landroid/content/pm/IPackageInstallerSession", - "Landroid/content/pm/PackageInstaller", - "Landroid/os/UserHandle" - ) - } val remotePackageManager = IPackageManager.Stub.asInterface( ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")) ) diff --git a/docs/guide/libsu.md b/docs/guide/libsu.md index 47a2d73ce..940ab38be 100644 --- a/docs/guide/libsu.md +++ b/docs/guide/libsu.md @@ -161,6 +161,38 @@ Also, you can use libsu for uninstall sessions: Plugin doesn't close the cached shell by itself to avoid interfering with other possible in-flight shell operations. +Hidden APIs +----------- + +This plugin initializes hidden Android API exemptions through AndroidX Startup using [LSPosed's HiddenApiBypass](https://github.com/LSPosed/AndroidHiddenApiBypass). In case you have your own additional exemptions: + +1. Disable the initializer in `AndroidManifest.xml`: + + ```xml + + + + ``` + +2. Add this list to your `HiddenApiBypass.setHiddenApiExemptions` call: + + ```kotlin + HiddenApiBypass.setHiddenApiExemptions( + "Landroid/content/pm/IPackageManager", + "Landroid/content/pm/IPackageInstaller", + "Landroid/content/pm/IPackageInstallerSession", + "Landroid/content/pm/PackageInstaller", + "Landroid/os/UserHandle", + "Landroid/os/ServiceManager" + ) + ``` + Plugin parameters ----------------- diff --git a/docs/guide/shizuku.md b/docs/guide/shizuku.md index 93630e504..f36f187f1 100644 --- a/docs/guide/shizuku.md +++ b/docs/guide/shizuku.md @@ -184,6 +184,38 @@ Also, you can use Shizuku for uninstall sessions: If Shizuku service is not running, or if Shizuku permission is not granted for your app, session will fail. +Hidden APIs +----------- + +This plugin initializes hidden Android API exemptions through AndroidX Startup using [LSPosed's HiddenApiBypass](https://github.com/LSPosed/AndroidHiddenApiBypass). In case you have your own additional exemptions: + +1. Disable the initializer in `AndroidManifest.xml`: + + ```xml + + + + ``` + +2. Add this list to your `HiddenApiBypass.setHiddenApiExemptions` call: + + ```kotlin + HiddenApiBypass.setHiddenApiExemptions( + "Landroid/content/pm/IPackageManager", + "Landroid/content/pm/IPackageInstaller", + "Landroid/content/pm/IPackageInstallerSession", + "Landroid/content/pm/PackageInstaller", + "Landroid/os/UserHandle", + "Landroid/os/ServiceManager" + ) + ``` + Plugin parameters ----------------- From fc181e0cc7571cc5dea4073e75e282b265613544 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Mon, 20 Jul 2026 09:04:43 +0500 Subject: [PATCH 2/4] fix incorrect installerPackageName capability report --- .../kotlin/ru/solrudev/ackpine/privileged/PrivilegedPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/PrivilegedPlugin.kt b/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/PrivilegedPlugin.kt index 9040ecc6f..dd2863f13 100644 --- a/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/PrivilegedPlugin.kt +++ b/ackpine-plugins/privileged/src/main/kotlin/ru/solrudev/ackpine/privileged/PrivilegedPlugin.kt @@ -69,7 +69,7 @@ public abstract class PrivilegedPlugin< requestDowngrade = isSupported, grantAllRequestedPermissions = isSupportedOnApi(Build.VERSION_CODES.M), allUsers = isSupported, - installerPackageName = isSupportedOnApi(Build.VERSION_CODES.P), + installerPackageName = isSupported, targetUser = isSupported ) ) From ef5039c485aeae5d6a089a3fe7dd3118f98c5750 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Mon, 20 Jul 2026 10:07:48 +0500 Subject: [PATCH 3/4] increment version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 8be537a69..7c06057c6 100644 --- a/version.json +++ b/version.json @@ -1,7 +1,7 @@ { "majorVersion": 0, "minorVersion": 25, - "patchVersion": 1, + "patchVersion": 2, "suffix": "", "isSnapshot": false } \ No newline at end of file From c9584d54bf3e6618f5ee06fb3cba56f384d81f6e Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Mon, 20 Jul 2026 10:09:15 +0500 Subject: [PATCH 4/4] add version 0.25.2 to changelog --- docs/changelog.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 913b0d086..3d403bf7e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,6 +6,14 @@ hide: Change Log ========== +Version 0.25.2 (2026-07-20) +--------------------------- + +### Bug fixes and improvements + +- Fix `installerPackageName` privileged plugins capability incorrectly reported as unsupported on API < 28. +- Set hidden API exemptions only once for all privileged plugins using AndroidX startup. On future Android versions, multiple calls to `HiddenApiBypass.setHiddenExemptions()` can result in a no-op or throw. If you have your own exemptions, disable Ackpine's privileged plugins exemptions initializer and add its exemptions list to your `setHiddenExemptions` call. See docs for details. + Version 0.25.1 (2026-07-20) ---------------------------