Add: Root session installer option

This commit is contained in:
machiav3lli 2022-05-07 03:09:12 +02:00
parent a0bf22ab70
commit 465b537d4f
6 changed files with 66 additions and 5 deletions

View File

@ -33,6 +33,7 @@ object Preferences {
Key.ProxyPort, Key.ProxyPort,
Key.ProxyType, Key.ProxyType,
Key.RootPermission, Key.RootPermission,
Key.RootSessionInstaller,
Key.SortOrder, Key.SortOrder,
Key.Theme, Key.Theme,
Key.DefaultTab, Key.DefaultTab,
@ -158,6 +159,7 @@ object Preferences {
) )
object RootPermission : Key<Boolean>("root_permission", Value.BooleanValue(false)) object RootPermission : Key<Boolean>("root_permission", Value.BooleanValue(false))
object RootSessionInstaller : Key<Boolean>("root_session_installer", Value.BooleanValue(false))
object SortOrder : Key<Preferences.SortOrder>( object SortOrder : Key<Preferences.SortOrder>(
"sort_order", "sort_order",

View File

@ -5,6 +5,9 @@ import android.content.Context
abstract class BaseInstaller(val context: Context) : InstallationEvents { abstract class BaseInstaller(val context: Context) : InstallationEvents {
companion object { companion object {
const val ROOT_INSTALL_PACKAGE = "cat %s | pm install -i %s --user %s -t -r -S %s" const val ROOT_INSTALL_PACKAGE = "cat %s | pm install -i %s --user %s -t -r -S %s"
const val ROOT_INSTALL_PACKAGE_SESSION_CREATE = "pm install-create -i %s --user %s -r -S %s"
const val ROOT_INSTALL_PACKAGE_SESSION_WRITE = "cat %s | pm install-write -S %s %s %s"
const val ROOT_INSTALL_PACKAGE_SESSION_COMMIT = "pm install-commit %s"
const val ROOT_UNINSTALL_PACKAGE = "pm uninstall --user %s %s" const val ROOT_UNINSTALL_PACKAGE = "pm uninstall --user %s %s"
const val DELETE_PACKAGE = "%s rm %s" const val DELETE_PACKAGE = "%s rm %s"
} }

View File

@ -1,12 +1,15 @@
package com.looker.droidify.installer package com.looker.droidify.installer
import android.content.Context import android.content.Context
import com.looker.droidify.BuildConfig
import com.looker.droidify.content.Cache import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.utility.extension.android.Android import com.looker.droidify.utility.extension.android.Android
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.util.regex.Pattern
class RootInstaller(context: Context) : BaseInstaller(context) { class RootInstaller(context: Context) : BaseInstaller(context) {
@ -41,6 +44,27 @@ class RootInstaller(context: Context) : BaseInstaller(context) {
length() length()
) )
val File.session_install_create
get() = String.format(
ROOT_INSTALL_PACKAGE_SESSION_CREATE,
BuildConfig.APPLICATION_ID,
getCurrentUserState,
length()
)
fun File.sessionInstallWrite(session_id: Int) = String.format(
ROOT_INSTALL_PACKAGE_SESSION_WRITE,
absolutePath,
length(),
session_id,
name
)
fun sessionInstallCommit(session_id: Int) = String.format(
ROOT_INSTALL_PACKAGE_SESSION_COMMIT,
session_id
)
val String.uninstall val String.uninstall
get() = String.format( get() = String.format(
ROOT_UNINSTALL_PACKAGE, ROOT_UNINSTALL_PACKAGE,
@ -66,14 +90,34 @@ class RootInstaller(context: Context) : BaseInstaller(context) {
mRootInstaller(cacheFile) mRootInstaller(cacheFile)
} }
override suspend fun install(packageName: String, cacheFile: File) = mRootInstaller(cacheFile) override suspend fun install(packageName: String, cacheFile: File) =
mRootInstaller(cacheFile)
override suspend fun uninstall(packageName: String) = mRootUninstaller(packageName) override suspend fun uninstall(packageName: String) = mRootUninstaller(packageName)
private suspend fun mRootInstaller(cacheFile: File) { private suspend fun mRootInstaller(cacheFile: File) {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
Shell.su(cacheFile.install) if (Preferences[Preferences.Key.RootSessionInstaller]) {
.submit { if (it.isSuccess) Shell.su(cacheFile.deletePackage).submit() } Shell.su(cacheFile.session_install_create)
.submit {
val sessionIdPattern = Pattern.compile("(\\d+)")
val sessionIdMatcher = sessionIdPattern.matcher(it.out[0])
val found = sessionIdMatcher.find()
if (found) {
val sessionId = sessionIdMatcher.group(1).toInt()
Shell.su(cacheFile.sessionInstallWrite(sessionId))
.submit {
Shell.su(sessionInstallCommit(sessionId)).exec()
if (it.isSuccess) Shell.su(cacheFile.deletePackage).submit()
}
}
}
} else {
Shell.su(cacheFile.install)
.submit { if (it.isSuccess) Shell.su(cacheFile.deletePackage).submit() }
}
} }
} }

View File

@ -29,7 +29,12 @@ import com.looker.droidify.R
import com.looker.droidify.content.Preferences import com.looker.droidify.content.Preferences
import com.looker.droidify.databinding.FragmentPrefsBinding import com.looker.droidify.databinding.FragmentPrefsBinding
import com.looker.droidify.databinding.PreferenceItemBinding import com.looker.droidify.databinding.PreferenceItemBinding
import com.looker.droidify.utility.extension.resources.* import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.TypefaceExtra
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.resources.inflate
import com.looker.droidify.utility.extension.resources.setTextSizeScaled
import com.looker.droidify.utility.extension.resources.sizeScaled
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -108,11 +113,12 @@ abstract class PrefsNavFragmentX : Fragment() {
preferences[Preferences.Key.ProxyHost]?.setEnabled(enabled) preferences[Preferences.Key.ProxyHost]?.setEnabled(enabled)
preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled) preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled)
} }
if (key == Preferences.Key.RootPermission) { if (key == null || key == Preferences.Key.RootPermission) {
preferences[Preferences.Key.RootPermission]?.setEnabled( preferences[Preferences.Key.RootPermission]?.setEnabled(
Shell.getCachedShell()?.isRoot Shell.getCachedShell()?.isRoot
?: Shell.getShell().isRoot ?: Shell.getShell().isRoot
) )
preferences[Preferences.Key.RootSessionInstaller]?.setEnabled(Utils.rootInstallerEnabled)
} }
if (key == Preferences.Key.Theme) { if (key == Preferences.Key.Theme) {
requireActivity().recreate() requireActivity().recreate()

View File

@ -51,6 +51,10 @@ class PrefsUpdatesFragment : PrefsNavFragmentX() {
Preferences.Key.RootPermission, getString(R.string.root_permission), Preferences.Key.RootPermission, getString(R.string.root_permission),
getString(R.string.root_permission_description) getString(R.string.root_permission_description)
) )
addSwitch(
Preferences.Key.RootSessionInstaller, getString(R.string.root_session_installer),
getString(R.string.root_session_installer_description)
)
} }
} }
} }

View File

@ -194,4 +194,6 @@
<string name="ignore_battery_optimization_not_supported">The device doesn\'t support ignoring battery optimizations!</string> <string name="ignore_battery_optimization_not_supported">The device doesn\'t support ignoring battery optimizations!</string>
<string name="dialog_refuse">Don\'t need it</string> <string name="dialog_refuse">Don\'t need it</string>
<string name="dialog_approve">Let\'s do it!</string> <string name="dialog_approve">Let\'s do it!</string>
<string name="root_session_installer">Use root session installer</string>
<string name="root_session_installer_description">The session installer is a bit less performant that the legacy one, but avoids issues with installed apps in Android +13.</string>
</resources> </resources>