-
-
Notifications
You must be signed in to change notification settings - Fork 23
chore: add validations to RootInstaller #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,4 @@ captures | |
.cxx | ||
local.properties | ||
xcuserdata | ||
node_modules/ | ||
node_modules/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
package app.revanced.library.installation.command | ||
|
||
import app.revanced.library.installation.command.ShellCommandRunner.ShellCommandRunnerException | ||
|
||
/** | ||
* The result of a command execution. | ||
*/ | ||
|
@@ -23,4 +25,11 @@ interface RunResult { | |
* Waits for the command to finish. | ||
*/ | ||
fun waitFor() {} | ||
|
||
/** | ||
* Verifies whether the command exits with code 0. | ||
* | ||
* @throws ShellCommandRunnerException if given [RunResult] exited unsuccessfully. | ||
*/ | ||
fun ensureSuccess() {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we don't need this as well as the exception because this looks like a high level API that isn't specific to commands or command runs. The installers can check for the exit code themselves or you can add a helper function to them to raise an exception. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,14 +19,14 @@ internal object Constants { | |
const val CREATE_INSTALLATION_PATH = "$CREATE_DIR $MOUNT_PATH" | ||
|
||
const val MOUNT_APK = | ||
"base_path=\"$MOUNTED_APK_PATH\" && " + | ||
"base_path='$MOUNTED_APK_PATH' && " + | ||
"mv $TMP_FILE_PATH \$base_path && " + | ||
"chmod 644 \$base_path && " + | ||
"chown system:system \$base_path && " + | ||
"chcon u:object_r:apk_data_file:s0 \$base_path" | ||
Comment on lines
21
to
26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use multiline string here and in other constants so that && can be removed, the line length reduced and readability improved. Also escaping " wont be needed anymore. .trimIndent() should be used then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already did that change and then reverted it. Think current code is readable enough and Single quotes for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What do you mean? Wouldn't running the commands in a new line also return the failure code Short multiple lines rather than a single long one is more readable, ideally this is applied here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By default, without the command1
command2
command3 would return 0 if only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not if command 1 or 3 failed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If only command1 and/or command2 failed, then the script would succeed as its exit code would be that of command3's - meaning successful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't command1 failing exit the script? From what I know if a line fails the lines below arent run. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not familiar with android, but in dash or bash, with default settings - no. That's what the |
||
|
||
const val UMOUNT = | ||
"grep $PLACEHOLDER /proc/mounts | " + | ||
"$MOUNT_GREP | " + | ||
laur89 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"while read -r line; do echo \$line | " + | ||
"cut -d ' ' -f 2 | " + | ||
"sed 's/apk.*/apk/' | " + | ||
|
@@ -56,7 +56,7 @@ internal object Constants { | |
|
||
# Use Magisk mirror, if possible. | ||
if command -v magisk &> /dev/null; then | ||
MIRROR="${'$'}(magisk --path)/.magisk/mirror" | ||
MIRROR="$(magisk --path)/.magisk/mirror" | ||
fi | ||
|
||
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,8 +16,6 @@ import app.revanced.library.installation.installer.Constants.RESTART | |
import app.revanced.library.installation.installer.Constants.TMP_FILE_PATH | ||
import app.revanced.library.installation.installer.Constants.UMOUNT | ||
import app.revanced.library.installation.installer.Constants.invoke | ||
import app.revanced.library.installation.installer.Installer.Apk | ||
import app.revanced.library.installation.installer.RootInstaller.NoRootPermissionException | ||
import java.io.File | ||
|
||
/** | ||
|
@@ -50,9 +48,8 @@ abstract class RootInstaller internal constructor( | |
* @throws PackageNameRequiredException If the [Apk] does not have a package name. | ||
*/ | ||
override suspend fun install(apk: Apk): RootInstallerResult { | ||
logger.info("Installing ${apk.packageName} by mounting") | ||
|
||
val packageName = apk.packageName?.also { it.assertInstalled() } ?: throw PackageNameRequiredException() | ||
logger.info("Installing ${apk.packageName} by mounting") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The throw should happen after the log as it would indicate that the attempt of the installation failed. This way this log would never occur when the throw would happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not see that log message prior to exception, as that can leave user confused as to whether any installation took place or not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The exception is raised. If not caught without logging anything, after the installation log, the exception will be shown. Otherwise the exception will be shown prior to letting the user know it occurred while installation. |
||
|
||
// Setup files. | ||
apk.file.move(TMP_FILE_PATH) | ||
|
@@ -61,8 +58,8 @@ abstract class RootInstaller internal constructor( | |
|
||
// Install and run. | ||
TMP_FILE_PATH.write(MOUNT_SCRIPT(packageName)) | ||
INSTALL_MOUNT_SCRIPT(packageName)().waitFor() | ||
MOUNT_SCRIPT_PATH(packageName)().waitFor() | ||
INSTALL_MOUNT_SCRIPT(packageName)().ensureSuccess() | ||
MOUNT_SCRIPT_PATH(packageName)().ensureSuccess() | ||
RESTART(packageName)() | ||
|
||
DELETE(TMP_FILE_PATH)() | ||
|
@@ -71,13 +68,17 @@ abstract class RootInstaller internal constructor( | |
} | ||
|
||
override suspend fun uninstall(packageName: String): RootInstallerResult { | ||
packageName.assertInstalled() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Attempting to unmount a pkg that's not even installed should surely throw. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line would need to be present in all implementations of Installer. This doesn't sound correctly abstracted |
||
if (MOUNT_GREP(packageName)().exitCode != 0) { | ||
throw NotMountedException() | ||
} | ||
Comment on lines
+72
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is to fail if user tries to unmount a pkg that's not mounted to begin with. IMHO indicates a user error that should be marked as such. As a downside makes the unmount command non-idempotent. Still has my vote though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think, if the user tries to uninstall an app that isn't installed, it's better to do it in good terms than in bad. An error is a bad term. Uninstallation finishing without doing anything, because nothing is mounted is a good term. |
||
logger.info("Uninstalling $packageName by unmounting") | ||
|
||
UMOUNT(packageName)() | ||
UMOUNT(packageName)().ensureSuccess() | ||
|
||
DELETE(MOUNTED_APK_PATH)(packageName)() | ||
DELETE(MOUNT_SCRIPT_PATH)(packageName)() | ||
DELETE(TMP_FILE_PATH)() // Remove residual. | ||
DELETE(TMP_FILE_PATH)() | ||
|
||
KILL(packageName)() | ||
|
||
|
@@ -131,4 +132,5 @@ abstract class RootInstaller internal constructor( | |
|
||
internal class PackageNameRequiredException internal constructor() : Exception("Package name is required") | ||
internal class NoRootPermissionException internal constructor() : Exception("No root permission") | ||
internal class NotMountedException internal constructor() : Exception("Package not mounted") | ||
} |
Uh oh!
There was an error while loading. Please reload this page.