-
-
Notifications
You must be signed in to change notification settings - Fork 27
feat: Magisk module install #127
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 3 commits
85dd550
9ba4e3e
a283be1
b180aea
6299737
647e7d6
bba8eb3
3e9dbc9
1d972f1
f6e0783
fa4e883
b026668
c2d57b7
35ab7dc
2c4a8d6
7b86534
08ac5dd
ed0c7a0
dda483b
e022803
09b39f8
277e368
754bddf
2e64ffd
e4c06cb
c229f11
3280af0
d27169d
3119114
fe6f102
650e952
e276095
d0f432e
041519a
84738bb
6fded1d
3d020fa
55f752c
b9d0a1b
995d155
b65883f
ce3e0e6
91c4b87
86887b2
dc438d2
547764d
d1f1076
2d19f45
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 |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| id=__PKG_NAME__-ReVanced | ||
| name=__LABEL__ ReVanced | ||
| version=__VERSION__ | ||
| versionCode=0 | ||
| author=ReVanced | ||
| description=Mounts the patched APK on top of the original one | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #!/system/bin/sh | ||
| DIR=${0%/*} | ||
|
|
||
| package_name="__PKG_NAME__" | ||
| version="__VERSION__" | ||
| sanitized_package_name=$(echo "$package_name" | sed 's/\./_/g') | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
|
|
||
| rm -f "$DIR/log" | ||
|
|
||
| { | ||
| echo "Induction check for $package_name" | ||
|
Member
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 does induction check mean
Member
Author
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. Basically making sure that the system is ready for the app to be injected/introduced into the system by overlaying on top of the original app
Member
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. But why "induction"
Member
Author
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. Just a mix of both, right now that whole name has been replaced by the watchdog and
Member
Author
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. Standardized naming on these commits |
||
|
|
||
| until [ "$(getprop sys.boot_completed)" = 1 ]; do sleep 5; done | ||
| # Wait a bit more for package manager to settle | ||
| sleep 10 | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
|
|
||
| base_path="$DIR/system/app/$sanitized_package_name/base.apk" | ||
| if [ ! -f "$base_path" ]; then | ||
| # Fallback to old path for compatibility during transition | ||
| base_path="$DIR/$package_name.apk" | ||
| fi | ||
|
|
||
| stock_path="$(pm path "$package_name" | grep base | sed 's/package://g' | head -n 1)" | ||
| stock_version="$(dumpsys package "$package_name" | grep versionName | cut -d "=" -f2 | head -n 1 | sed 's/ //g')" | ||
|
|
||
| echo "base_path: $base_path" | ||
| echo "stock_path: $stock_path" | ||
| echo "base_version: $version" | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| echo "stock_version: $stock_version" | ||
|
|
||
| if [ -z "$stock_path" ]; then | ||
| echo "App $package_name is not installed. System app induction might have failed or still being processed." | ||
| exit 1 | ||
| fi | ||
|
|
||
| if echo "$stock_path" | grep -q "^/system/"; then | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| echo "App is already running from system partition (likely our Magisk overlay). Skipping bind mount." | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| exit 0 | ||
| fi | ||
|
|
||
| if mount | grep -q "$stock_path" ; then | ||
| echo "Not mounting as stock path is already mounted" | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| exit 1 | ||
| fi | ||
|
|
||
| if [ "$version" != "$stock_version" ]; then | ||
| echo "Version mismatch: base=$version, stock=$stock_version. Attempting to mount anyway as it might be a minor diff." | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| # Optional: exit 1 if you want to be strict | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| fi | ||
|
|
||
| echo "Mounting $base_path over $stock_path" | ||
| mount -o bind "$base_path" "$stock_path" | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
|
|
||
| } >> "$DIR/log" | ||
|
secp192k1 marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,233 @@ | ||
| package app.revanced.library | ||
|
|
||
| import android.content.res.AssetManager | ||
| import com.topjohnwu.superuser.Shell | ||
| import com.topjohnwu.superuser.nio.FileSystemManager | ||
| import java.io.File | ||
| import java.util.zip.ZipFile | ||
|
|
||
| object MagiskUtils { | ||
|
Member
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. can be internal no?
Member
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. Actually looks like these are APIs for callsite? Why are they needed?
Member
Author
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 got an error while testing patching with youtube, it failed to load since there were missing native libraries, so this basically includes the necessary libs
Member
Author
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. And MagiskUtils is used directly by the manager, so it can't be internal
Member
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. APIs in library should only exist in library if they can/should be shared with cli too, but i cant see how this would apply for a couple of apis introduced here.
Member
Author
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.
MagiskUtils is called directly from the manager's RootInstaller for live mount & unmount operations in a coroutine scope, so it must stay public
Understandable but for android specific APIs like prepareMagiskModule & extractNativeLibraries don't make sense for CLI imo, but we could always move it into manager as a specialized internal helper if you want
Member
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.
Manager should not require any live mount/unmount operations at all, this is business logic of the library installer that manager should use and not reimplement. So The APIs here should be designed to reflect that.
Why not? CLI can prepare a magisk module via ADB too? |
||
| const val MODULES_PATH = "/data/adb/modules" | ||
|
|
||
| fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false | ||
|
|
||
| fun isDeviceRooted() = | ||
| System.getenv("PATH")?.split(":")?.any { path -> File(path, "su").canExecute() } ?: false | ||
|
|
||
| fun isInstalled(packageName: String, remoteFS: FileSystemManager) = | ||
| remoteFS.getFile("$MODULES_PATH/$packageName-revanced").exists() | ||
|
|
||
| fun isInstalledAsMagiskModule(packageName: String, remoteFS: FileSystemManager) = | ||
| remoteFS.getFile("$MODULES_PATH/revanced_${packageName.replace('.', '_')}").exists() | ||
|
|
||
| fun mount(packageName: String, sourceDir: String) { | ||
|
Member
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 is this function needed? Installers already implement it
Member
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. Like all these utils functions below
Member
Author
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. These are called from the manager's own RootInstaller for live mounts outside the library's install lifecycle (re-mounting on app launch without reinstalling). The library installers handle their own mounting on the installation flow
Member
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 dont think manager should have this feature, in which case the utils function should be removable no?
Member
Author
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.
Sorry but I dont get what you meant here, I guess you want to get rid of the mount & unmount from the manager and directly call those 2 functions on library?
Member
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.
Basically, manager should not provide in-place mount & unmount options. Installation and uninstallation over mount is handled by installers which manager is supposed to call. |
||
| val modulePath = "$MODULES_PATH/$packageName-revanced" | ||
| val patchedApk = "$modulePath/$packageName.apk" | ||
| Shell.getShell().newJob() | ||
| .add("mount -o bind \"$patchedApk\" \"$sourceDir\"") | ||
| .exec() | ||
| .assertSuccess("Failed to mount APK") | ||
| } | ||
|
|
||
| fun unmount(sourceDir: String) { | ||
| Shell.getShell().newJob() | ||
| .add("umount -l \"$sourceDir\"") | ||
| .exec() | ||
| .assertSuccess("Failed to unmount APK") | ||
| } | ||
|
|
||
| fun uninstall(packageName: String, remoteFS: FileSystemManager) { | ||
| remoteFS.getFile("$MODULES_PATH/$packageName-revanced").deleteRecursively() | ||
| .also { if (!it) throw Exception("Failed to delete files") } | ||
| } | ||
|
|
||
| fun uninstallMagiskModule(packageName: String, remoteFS: FileSystemManager) { | ||
| val sanitizedPackageName = packageName.replace('.', '_') | ||
| remoteFS.getFile("$MODULES_PATH/revanced_$sanitizedPackageName").deleteRecursively() | ||
| .also { if (!it) throw Exception("Failed to delete Magisk module files") } | ||
| } | ||
|
|
||
| fun extractNativeLibraries(apkFile: File, systemAppPath: String, remoteFS: FileSystemManager) { | ||
|
Member
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 is this needed?
Member
Author
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. Its needed since it can raise an exception when installing/mounting the app, I've mentioned this exact issue somewhere else on the comments
Member
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 cant find the comment, how/why does it raise an error?
Member
Author
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.
#127 (comment)
Member
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 is that thrown when mounting? And how does extractNativeLibraries fix it
Member
Author
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.
Correct for libs that exist in both the unpatched/stock and patched APKs. The issue is when the patched APK introduces new .so file(s) that were never in the stock APK (i.e libelements.so in YT), PM never extracted those, so dlopen can't find them - only case extractNativeLibraries handles
Member
Author
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.
For system apps yes but revanced targets user-installed apps (
Member
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.
Understandable, however i dont think youre exhausting everything that needs mounting no? Is there anything else besides the base apk and the libs we would have to handle in mounting? Granted this including the extractNativeLibraries function are not in scope of this PR, but if you want to introduce this feature here, this functionality shouldve been implemented in RootInstaller class on install/uninstall and not just MagiskUtils.
Member
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.
Actually we dont constrain any target. Mounting installation follows this:
Where the location is is not in our responsibility. It should work anywhere where the app is installed. I could create a ROM which ships e.g. yt as a system app. So, if we patch and mount it, it should work correctly.
Member
Author
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.
Correct, the mount path already does this, the manager reads applicationInfo.sourceDir at runtime, so it naturally follows wherever the app is installed, whether its /data/app or /system/app The system-app caveat I mentioned was specifically about extractNativeLibraries() writing to the lib directory on a read-only system partition. But not longer an "issue" since 754bddf the module path uses pm install, so PM handles lib extraction automatically, and the function has been removed in b9d0a1b |
||
| val libPath = "$systemAppPath/lib" | ||
| remoteFS.getFile(libPath).apply { | ||
| if (exists()) deleteRecursively() | ||
| mkdirs() | ||
| } | ||
|
|
||
| ZipFile(apkFile).use { zip -> | ||
| zip.entries().asSequence() | ||
| .filter { it.name.startsWith("lib/") && it.name.endsWith(".so") } | ||
| .forEach { entry -> | ||
| val parts = entry.name.split("/") | ||
| if (parts.size < 3) return@forEach | ||
|
|
||
| val apkAbi = parts[1] | ||
| val libName = parts.last() | ||
| val systemAbi = when (apkAbi) { | ||
| "arm64-v8a" -> "arm64" | ||
| "armeabi-v7a" -> "arm" | ||
| "x86_64" -> "x86_64" | ||
| "x86" -> "x86" | ||
| else -> apkAbi | ||
| } | ||
|
|
||
| val targetDir = "$libPath/$systemAbi" | ||
| remoteFS.getFile(targetDir).apply { if (!exists()) mkdirs() } | ||
|
|
||
| val targetFile = "$targetDir/$libName" | ||
| zip.getInputStream(entry).use { inputStream -> | ||
| remoteFS.getFile(targetFile).newOutputStream().use { outputStream -> | ||
| inputStream.copyTo(outputStream) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fun provisionMagiskModule( | ||
|
Member
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. stage/prepare/provision decide haha (use prepare, simpler)
Member
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 --user 0 should also be removed from that command above it, ReVanced/revanced-manager#3288
Member
Author
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.
|
||
| remoteFS: FileSystemManager, | ||
| assets: AssetManager, | ||
| packageName: String, | ||
| version: String, | ||
| label: String, | ||
| patchedApk: File | ||
| ) { | ||
| val sanitizedPackageName = packageName.replace('.', '_') | ||
| val modulePath = "$MODULES_PATH/revanced_$sanitizedPackageName" | ||
| val systemAppPath = "$modulePath/system/app/$sanitizedPackageName" | ||
|
|
||
| Shell.getShell().newJob() | ||
| .add("mkdir -p \"$systemAppPath\"") | ||
| .exec() | ||
| .assertSuccess("Failed to create system app directory") | ||
|
|
||
| val moduleProp = buildString { | ||
| appendLine("id=revanced_$sanitizedPackageName") | ||
| appendLine("name=$label ReVanced") | ||
| appendLine("version=$version") | ||
| appendLine("versionCode=1") | ||
| appendLine("author=ReVanced") | ||
| append("description=Patched by ReVanced") | ||
| } | ||
| remoteFS.getFile("$modulePath/module.prop").newOutputStream().use { it.write(moduleProp.toByteArray()) } | ||
|
|
||
| assets.open("root/service.sh").use { inputStream -> | ||
| remoteFS.getFile("$modulePath/service.sh").newOutputStream().use { outputStream -> | ||
| val content = String(inputStream.readBytes()) | ||
| .replace("__PKG_NAME__", packageName) | ||
| .replace("__VERSION__", version) | ||
| .replace("__LABEL__", label) | ||
| .toByteArray() | ||
| outputStream.write(content) | ||
| } | ||
| } | ||
|
|
||
| val targetApkPath = "$systemAppPath/base.apk" | ||
| remoteFS.getFile(patchedApk.absolutePath) | ||
| .also { if (!it.exists()) throw Exception("File doesn't exist") } | ||
| .newInputStream().use { inputStream -> | ||
| remoteFS.getFile(targetApkPath).newOutputStream().use { outputStream -> | ||
| inputStream.copyTo(outputStream) | ||
| } | ||
| } | ||
|
|
||
| extractNativeLibraries(patchedApk, systemAppPath, remoteFS) | ||
|
|
||
| Shell.getShell().newJob() | ||
| .add("chmod 644 \"$targetApkPath\"") | ||
| .add("chmod 755 \"$systemAppPath\"") | ||
| .add("chmod -R 755 \"$systemAppPath/lib\"") | ||
| .add("find \"$systemAppPath/lib\" -type f -name \"*.so\" -exec chmod 644 {} +") | ||
| .add("chown -R system:system \"$modulePath/system\"") | ||
| .add("chcon -R u:object_r:system_file:s0 \"$modulePath/system\"") | ||
| .add("chmod +x \"$modulePath/service.sh\"") | ||
| .exec() | ||
| .assertSuccess("Failed to set file permissions") | ||
| } | ||
|
|
||
| fun provisionRootFolder( | ||
| remoteFS: FileSystemManager, | ||
| assets: AssetManager, | ||
| packageName: String, | ||
| version: String, | ||
| label: String, | ||
| patchedApk: File | ||
| ) { | ||
| val modulePath = "$MODULES_PATH/$packageName-revanced" | ||
| remoteFS.getFile(modulePath).apply { | ||
| if (!mkdirs() && !exists()) { | ||
| throw Exception("Failed to create module directory") | ||
| } | ||
| } | ||
|
|
||
| listOf( | ||
| "service.sh", | ||
| "module.prop", | ||
| ).forEach { file -> | ||
| assets.open("root/$file").use { inputStream -> | ||
| remoteFS.getFile("$modulePath/$file").newOutputStream().use { outputStream -> | ||
| val content = String(inputStream.readBytes()) | ||
| .replace("__PKG_NAME__", packageName) | ||
| .replace("__VERSION__", version) | ||
| .replace("__LABEL__", label) | ||
| .toByteArray() | ||
| outputStream.write(content) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| val apkPath = "$modulePath/$packageName.apk" | ||
| remoteFS.getFile(patchedApk.absolutePath) | ||
| .also { if (!it.exists()) throw Exception("File doesn't exist") } | ||
| .newInputStream().use { inputStream -> | ||
| remoteFS.getFile(apkPath).newOutputStream().use { outputStream -> | ||
| inputStream.copyTo(outputStream) | ||
| } | ||
| } | ||
|
|
||
| Shell.getShell().newJob() | ||
| .add("chmod 644 \"$apkPath\"") | ||
| .add("chown system:system \"$apkPath\"") | ||
| .add("chcon u:object_r:apk_data_file:s0 \"$apkPath\"") | ||
| .add("chmod +x \"$modulePath/service.sh\"") | ||
| .exec() | ||
| .assertSuccess("Failed to set file permissions") | ||
| } | ||
|
|
||
| private fun Shell.Result.assertSuccess(errorMessage: String) { | ||
| if (!isSuccess) { | ||
| throw ShellCommandException(errorMessage, code, out, err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| class ShellCommandException( | ||
| val userMessage: String, | ||
| val exitCode: Int, | ||
| val stdout: List<String>, | ||
| val stderr: List<String> | ||
| ) : Exception(format(userMessage, exitCode, stdout, stderr)) { | ||
| companion object { | ||
| private fun format( | ||
| message: String, | ||
| exitCode: Int, | ||
| stdout: List<String>, | ||
| stderr: List<String> | ||
| ): String = buildString { | ||
| appendLine(message) | ||
| appendLine("Exit code: $exitCode") | ||
|
|
||
| val output = stdout.filter { it.isNotBlank() } | ||
| val errors = stderr.filter { it.isNotBlank() } | ||
|
|
||
| if (output.isNotEmpty()) { | ||
| appendLine("stdout:") | ||
| output.forEach(::appendLine) | ||
| } | ||
| if (errors.isNotEmpty()) { | ||
| appendLine("stderr:") | ||
| errors.forEach(::appendLine) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package app.revanced.library.installation.installer | ||
|
|
||
| import android.content.Context | ||
| import app.revanced.library.installation.command.LocalShellCommandRunner | ||
| import com.topjohnwu.superuser.ipc.RootService | ||
| import java.io.Closeable | ||
|
|
||
| /** | ||
| * [LocalMagiskInstaller] for installing and uninstalling [Apk] files locally with root permissions via Magisk modules. | ||
| * | ||
| * @param context The [Context] to use for binding to the [RootService]. | ||
| * @param onReady A callback to be invoked when [LocalMagiskInstaller] is ready to be used. | ||
| * | ||
| * @throws NoRootPermissionException If the device does not have root permission. | ||
| * | ||
| * @see Installer | ||
| * @see LocalShellCommandRunner | ||
| */ | ||
| @Suppress("unused") | ||
| class LocalMagiskInstaller( | ||
| context: Context, | ||
| onReady: LocalMagiskInstaller.() -> Unit = {}, | ||
| ) : MagiskInstaller( | ||
|
Member
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. Hm, Is there any reason why this class does not extend LocalRootInstaller? MagiskRootInstaller : RootInstaller No?
Member
Author
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. Basically from here #127 (comment) |
||
| { installer -> | ||
| LocalShellCommandRunner(context) { | ||
| (installer as LocalMagiskInstaller).onReady() | ||
| } | ||
| }, | ||
| ), | ||
| Closeable { | ||
| override fun close() = (shellCommandRunner as LocalShellCommandRunner).close() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package app.revanced.library.installation.installer | ||
|
|
||
| import app.revanced.library.installation.command.AdbShellCommandRunner | ||
|
|
||
| /** | ||
| * [AdbMagiskInstaller] for installing and uninstalling [Apk] files using ADB root permissions via Magisk modules. | ||
| * | ||
| * @param deviceSerial The device serial. If null, the first connected device will be used. | ||
| * | ||
| * @throws NoRootPermissionException If the device does not have root permission. | ||
| * | ||
| * @see MagiskInstaller | ||
| * @see AdbShellCommandRunner | ||
| */ | ||
| class AdbMagiskInstaller( | ||
| deviceSerial: String? = null, | ||
| ) : MagiskInstaller({ AdbShellCommandRunner(deviceSerial) }) { | ||
| init { | ||
| logger.fine("Connected to $deviceSerial") | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,26 @@ internal object Constants { | |
| const val CREATE_INSTALLATION_PATH = "$CREATE_DIR $MOUNT_PATH" | ||
| const val GET_SDK_VERSION = "getprop ro.build.version.sdk" | ||
|
|
||
| const val MAGISK_MODULES_PATH = "/data/adb/modules/" | ||
|
secp192k1 marked this conversation as resolved.
Outdated
oSumAtrIX marked this conversation as resolved.
Outdated
|
||
| const val MAGISK_MODULE_ID = "revanced_$PLACEHOLDER" | ||
|
secp192k1 marked this conversation as resolved.
Outdated
Member
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. Any reason why this isnt inlined, seems to be used in one place only
Member
Author
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. Done |
||
| const val MAGISK_MODULE_PATH = "$MAGISK_MODULES_PATH$MAGISK_MODULE_ID" | ||
|
|
||
| const val COPY_APK_TO_MODULE = | ||
|
secp192k1 marked this conversation as resolved.
Outdated
secp192k1 marked this conversation as resolved.
Outdated
|
||
| "cp $TMP_FILE_PATH $PLACEHOLDER && " + | ||
| "chmod 644 $PLACEHOLDER && " + | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| "chown system:system $PLACEHOLDER && " + | ||
| "chcon $SELINUX_CONTEXT $PLACEHOLDER" | ||
|
|
||
| val MAGISK_MODULE_PROP = | ||
|
secp192k1 marked this conversation as resolved.
Outdated
|
||
| $$""" | ||
| id=$$MAGISK_MODULE_ID | ||
| name=ReVanced $$PLACEHOLDER | ||
| version=1.0 | ||
| versionCode=1 | ||
| author=ReVanced | ||
| description=Patched by ReVanced | ||
| """.trimIndent() | ||
|
|
||
| const val MOUNT_APK = | ||
| "base_path=\"$MOUNTED_APK_PATH\" && " + | ||
| $$"mv $$TMP_FILE_PATH $base_path && " + | ||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.