Implement Shizuku installer support

This commit is contained in:
grrfe
2023-06-15 17:28:05 +02:00
committed by Aayush Gupta
parent b4c4ac7cef
commit 20a0bea246
11 changed files with 236 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
* Copyright (C) 2023, grrfe <grrfe@420blaze.it>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +26,7 @@ import android.os.Build
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDexApplication
import com.aurora.Constants
import com.aurora.extensions.isPAndAbove
import com.aurora.store.data.downloader.DownloadManager
import com.aurora.store.data.providers.NetworkProvider
import com.aurora.store.data.receiver.PackageManagerReceiver
@@ -35,6 +37,7 @@ import com.tonyodev.fetch2.Fetch
import java.util.ArrayList
import nl.komponents.kovenant.android.startKovenant
import nl.komponents.kovenant.android.stopKovenant
import org.lsposed.hiddenapibypass.HiddenApiBypass
class AuroraApplication : MultiDexApplication() {
@@ -48,6 +51,12 @@ class AuroraApplication : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
// TODO: Only exempt required APIs
// Required for Shizuku installer
if (isPAndAbove()) {
HiddenApiBypass.addHiddenApiExemptions("")
}
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
//Create Notification Channels : General & Alert

View File

@@ -1,6 +1,7 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
* Copyright (C) 2023, grrfe <grrfe@420blaze.it>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,13 +22,16 @@ package com.aurora.store.data.installer
import android.content.Context
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import com.aurora.extensions.isLAndAbove
import com.aurora.extensions.isOAndAbove
import com.aurora.store.BuildConfig
import com.aurora.store.R
import com.aurora.store.util.PackageUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID
import com.topjohnwu.superuser.Shell
import rikka.shizuku.Shizuku
open class AppInstaller private constructor(var context: Context) {
@@ -75,6 +79,15 @@ open class AppInstaller private constructor(var context: Context) {
return PackageUtil.isInstalled(context, AMInstaller.AM_PACKAGE_NAME) or
PackageUtil.isInstalled(context, AMInstaller.AM_DEBUG_PACKAGE_NAME)
}
fun hasShizuku(context: Context): Boolean {
return PackageUtil.isInstalled(context, ShizukuInstaller.SHIZUKU_PACKAGE_NAME)
}
fun hasShizukuPerm(): Boolean {
return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
}
}
val choiceAndInstaller = HashMap<Int, IInstaller>()
@@ -122,6 +135,19 @@ open class AppInstaller private constructor(var context: Context) {
choiceAndInstaller[prefValue] = installer
installer
}
5 -> {
if (isOAndAbove()) {
val installer = if (hasShizuku(context) && hasShizukuPerm()) {
ShizukuInstaller(context)
} else {
getDefaultInstaller(context)
}
choiceAndInstaller[prefValue] = installer
installer
} else {
getDefaultInstaller(context)
}
}
else -> {
val installer = getDefaultInstaller(context)
choiceAndInstaller[prefValue] = installer

View File

@@ -0,0 +1,99 @@
/*
* Aurora Store
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
*
* Aurora Store is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Aurora Store is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.aurora.store.data.installer
import android.content.Context
import android.content.pm.*
import android.content.pm.PackageInstaller.SessionParams
import android.os.Build
import android.os.IBinder
import android.os.IInterface
import androidx.annotation.RequiresApi
import com.aurora.extensions.isOAndAbove
import com.aurora.extensions.isSAndAbove
import com.aurora.store.R
import com.aurora.store.util.Log
import dev.rikka.tools.refine.Refine
import rikka.shizuku.ShizukuBinderWrapper
import rikka.shizuku.SystemServiceHelper
class ShizukuInstaller(context: Context) : SessionInstallerBase(context) {
companion object {
const val SHIZUKU_PACKAGE_NAME = "moe.shizuku.privileged.api"
}
// Taken from LSPatch (https://github.com/LSPosed/LSPatch)
private fun IBinder.wrap() = ShizukuBinderWrapper(this)
private fun IInterface.asShizukuBinder() = this.asBinder().wrap()
private val iPackageManager: IPackageManager by lazy {
IPackageManager.Stub.asInterface(SystemServiceHelper.getSystemService("package").wrap())
}
private val iPackageInstaller: IPackageInstaller by lazy {
IPackageInstaller.Stub.asInterface(iPackageManager.packageInstaller.asShizukuBinder())
}
private val packageInstaller: PackageInstaller? by lazy {
if (isSAndAbove()) {
Refine.unsafeCast<PackageInstaller>(
PackageInstallerHidden(iPackageInstaller, "com.android.vending", null, 0)
)
} else if (isOAndAbove()) {
Refine.unsafeCast<PackageInstaller>(
PackageInstallerHidden(iPackageInstaller, "com.android.vending", 0)
)
} else null
}
@RequiresApi(Build.VERSION_CODES.O)
override fun install(packageName: String, files: List<Any>) {
if (isAlreadyQueued(packageName)) {
Log.i("$packageName already queued")
} else {
Log.i("Received session install request for $packageName")
val (sessionId, session) = kotlin.runCatching {
val sessionId =
packageInstaller!!.createSession(SessionParams(SessionParams.MODE_FULL_INSTALL))
val iSession = IPackageInstallerSession.Stub.asInterface(
iPackageInstaller.openSession(sessionId).asShizukuBinder()
)
val session = Refine.unsafeCast<PackageInstaller.Session>(
PackageInstallerHidden.SessionHidden(iSession)
)
sessionId to session
}.getOrElse { ex ->
ex.printStackTrace()
postError(
packageName,
context.getString(R.string.installer_status_failure),
context.getString(R.string.installer_shizuku_unavailable)
)
return
}
xInstall(sessionId, session, packageName, files)
}
}
}

View File

@@ -19,17 +19,21 @@
package com.aurora.store.view.ui.onboarding
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.aurora.extensions.isMIUI
import com.aurora.extensions.isMiuiOptimizationDisabled
import com.aurora.extensions.isOAndAbove
import com.aurora.extensions.showDialog
import com.aurora.store.R
import com.aurora.store.data.installer.AppInstaller.Companion.hasAppManager
import com.aurora.store.data.installer.AppInstaller.Companion.hasRootAccess
import com.aurora.store.data.installer.AppInstaller.Companion.hasAuroraService
import com.aurora.store.data.installer.AppInstaller.Companion.hasShizuku
import com.aurora.store.data.installer.AppInstaller.Companion.hasShizukuPerm
import com.aurora.store.data.model.Installer
import com.aurora.store.databinding.FragmentOnboardingInstallerBinding
import com.aurora.store.util.Preferences
@@ -39,6 +43,7 @@ import com.aurora.store.view.epoxy.views.preference.InstallerViewModel_
import com.aurora.store.view.ui.commons.BaseFragment
import com.aurora.store.view.ui.sheets.DeviceMiuiSheet
import com.google.gson.reflect.TypeToken
import rikka.shizuku.Shizuku
import java.nio.charset.StandardCharsets
@@ -48,11 +53,25 @@ class InstallerFragment : BaseFragment() {
var installerId: Int = 0
private val shizukuResultListener =
Shizuku.OnRequestPermissionResultListener { _: Int, result: Int ->
if (result == PackageManager.PERMISSION_GRANTED) {
this.installerId = 5
save(PREFERENCE_INSTALLER_ID, 5)
} else {
showDialog(
R.string.action_installations,
R.string.installer_shizuku_unavailable
)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
Shizuku.addRequestPermissionResultListener(shizukuResultListener)
B = FragmentOnboardingInstallerBinding.bind(
inflater.inflate(
R.layout.fragment_onboarding_installer,
@@ -76,6 +95,11 @@ class InstallerFragment : BaseFragment() {
updateController(installerList)
}
override fun onDestroy() {
Shizuku.removeRequestPermissionResultListener(shizukuResultListener)
super.onDestroy()
}
private fun updateController(installerList: List<Installer>) {
B.epoxyRecycler.withModels {
setFilterDuplicates(true)
@@ -140,6 +164,26 @@ class InstallerFragment : BaseFragment() {
)
}
}
5 -> {
if (hasShizuku(requireContext()) && isOAndAbove()) {
if (hasShizukuPerm()) {
this.installerId = installerId
save(PREFERENCE_INSTALLER_ID, installerId)
} else if (Shizuku.shouldShowRequestPermissionRationale()) {
Shizuku.requestPermission(9000)
} else {
showDialog(
R.string.action_installations,
R.string.installer_shizuku_unavailable
)
}
} else {
showDialog(
R.string.action_installations,
R.string.installer_shizuku_unavailable
)
}
}
else -> {
this.installerId = installerId
save(PREFERENCE_INSTALLER_ID, installerId)

View File

@@ -19,6 +19,7 @@
package com.aurora.store.view.ui.preferences
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import androidx.preference.Preference
@@ -30,12 +31,14 @@ import com.aurora.store.BuildConfig
import com.aurora.store.R
import com.aurora.store.data.installer.AMInstaller
import com.aurora.store.data.installer.ServiceInstaller
import com.aurora.store.data.installer.ShizukuInstaller
import com.aurora.store.util.CommonUtil
import com.aurora.store.util.PackageUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.save
import com.aurora.store.view.custom.preference.AuroraListPreference
import com.topjohnwu.superuser.Shell
import rikka.shizuku.Shizuku
class InstallationPreference : PreferenceFragmentCompat() {
@@ -100,6 +103,17 @@ class InstallationPreference : PreferenceFragmentCompat() {
)
false
}
} else if (selectedId == 5) {
if (checkShizukuAvailability()) {
save(Preferences.PREFERENCE_INSTALLER_ID, selectedId)
true
} else {
showDialog(
R.string.action_installations,
R.string.installer_shizuku_unavailable
)
false
}
} else {
save(Preferences.PREFERENCE_INSTALLER_ID, selectedId)
true
@@ -137,4 +151,9 @@ class InstallationPreference : PreferenceFragmentCompat() {
AMInstaller.AM_DEBUG_PACKAGE_NAME
)
}
private fun checkShizukuAvailability(): Boolean {
return PackageUtil.isInstalled(requireContext(), ShizukuInstaller.SHIZUKU_PACKAGE_NAME) &&
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
}
}