Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ android {

buildTypes {
debug {
applicationIdSuffix = ".debug"
buildConfigField("long", "BUILD_ID", "${Random.nextLong()}L")
}

Expand Down Expand Up @@ -218,7 +219,6 @@ android {
)

jniLibs {
excludes += "/lib/x86/*.so"
useLegacyPackaging = true
}
}
Expand Down Expand Up @@ -258,6 +258,7 @@ kotlin {
freeCompilerArgs.addAll(
"-Xexplicit-backing-fields",
"-Xcontext-parameters",
"-opt-in=kotlin.time.ExperimentalTime"
)
}
}
Expand Down
19 changes: 19 additions & 0 deletions app/google-services.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@
"other_platform_oauth_client": []
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:574971415597:android:5acf99d4cc8260eedc7ca4",
"android_client_info": {
"package_name": "app.morphe.manager.debug"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAICrE-tnEhNKXh1vEbfucYWWxOr7NSr_g"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
Expand Down
4 changes: 4 additions & 0 deletions app/src/debug/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Morphe Debug</string>
</resources>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.morphe.manager.domain.manager

import android.app.ActivityManager
import android.content.Context
import android.os.Build
import android.util.Log
Expand All @@ -15,6 +16,7 @@ import app.morphe.manager.ui.viewmodel.BundleSnapshot
import app.morphe.manager.util.isArmV7
import app.morphe.manager.util.tag
import app.morphe.manager.worker.UpdateCheckInterval
import app.morphe.patcher.dex.BytecodeMode
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.Serializable

Expand Down Expand Up @@ -58,6 +60,15 @@ class PreferencesManager(

val stripUnusedNativeLibs = booleanPreference("strip_unused_native_libs", false)

/**
* Bytecode processing mode for the patcher.
* Defaults to [BytecodeMode.STRIP_FAST].
*/
val bytecodeModePreference = enumPreference(
"bytecode_mode",
BytecodeMode.STRIP_FAST
)

// System tab
val installerPrimary = stringPreference("installer_primary", InstallerPreferenceTokens.INTERNAL)
val promptInstallerOnInstall = booleanPreference("prompt_installer_on_install", false)
Expand Down Expand Up @@ -164,6 +175,7 @@ class PreferencesManager(
val backgroundUpdateNotifications: Boolean? = null,
val updateCheckInterval: UpdateCheckInterval? = null,
val customBundles: List<BundleSnapshot>? = null,
val bytecodeModePreference: BytecodeMode? = null,
)

suspend fun exportSettings() = SettingsSnapshot(
Expand Down Expand Up @@ -194,7 +206,8 @@ class PreferencesManager(
backgroundType = backgroundType.get(),
useExpertMode = useExpertMode.get(),
backgroundUpdateNotifications = backgroundUpdateNotifications.get(),
updateCheckInterval = updateCheckInterval.get()
updateCheckInterval = updateCheckInterval.get(),
bytecodeModePreference = bytecodeModePreference.get(),
)

suspend fun importSettings(snapshot: SettingsSnapshot) = edit {
Expand Down Expand Up @@ -226,6 +239,7 @@ class PreferencesManager(
snapshot.useExpertMode?.let { useExpertMode.value = it }
snapshot.backgroundUpdateNotifications?.let { backgroundUpdateNotifications.value = it }
snapshot.updateCheckInterval?.let { updateCheckInterval.value = it }
snapshot.bytecodeModePreference?.let { bytecodeModePreference.value = it }
}

companion object {
Expand Down
7 changes: 4 additions & 3 deletions app/src/main/java/app/morphe/manager/patcher/Session.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import app.morphe.manager.patcher.Session.Companion.component1
import app.morphe.manager.patcher.Session.Companion.component2
import app.morphe.manager.patcher.logger.Logger
import app.morphe.manager.ui.model.State
import app.morphe.patcher.dex.BytecodeMode
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.Closeable
Expand All @@ -23,12 +24,12 @@ internal typealias PatchList = List<Patch<*>>
class Session(
cacheDir: String,
frameworkDir: String,
aaptPath: String,
private val androidContext: Context,
private val logger: Logger,
private val input: File,
private val onPatchCompleted: suspend () -> Unit,
private val onProgress: (name: String?, state: State?, message: String?) -> Unit
private val onProgress: (name: String?, state: State?, message: String?) -> Unit,
bytecodeMode: BytecodeMode = BytecodeMode.STRIP_FAST,
) : Closeable {
private fun updateProgress(name: String? = null, state: State? = null, message: String? = null) =
onProgress(name, state, message)
Expand All @@ -39,7 +40,7 @@ class Session(
apkFile = input,
temporaryFilesPath = tempDir,
frameworkFileDirectory = frameworkDir,
aaptBinaryPath = aaptPath
useBytecodeMode = bytecodeMode,
)
)

Expand Down
12 changes: 0 additions & 12 deletions app/src/main/java/app/morphe/manager/patcher/aapt/Aapt.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,67 +29,69 @@ class CoroutineRuntime(private val context: Context) : Runtime(context) {
) {
MemoryMonitor.startMemoryPolling(logger)

val selectedBundles = selectedPatches.keys
val bundles = bundles()
val uids = bundles.entries.associate { (key, value) -> value to key }
try {
val selectedBundles = selectedPatches.keys
val bundles = bundles()
val uids = bundles.entries.associate { (key, value) -> value to key }

val allPatches =
PatchBundle.Loader.patches(bundles.values, packageName)
.mapKeys { (b, _) -> uids[b]!! }
.filterKeys { it in selectedBundles }
val allPatches =
PatchBundle.Loader.patches(bundles.values, packageName)
.mapKeys { (b, _) -> uids[b]!! }
.filterKeys { it in selectedBundles }

val patchList = selectedPatches.flatMap { (bundle, selected) ->
allPatches[bundle]?.filter { it.name in selected }
?: throw IllegalArgumentException("Patch bundle $bundle does not exist")
}
val patchList = selectedPatches.flatMap { (bundle, selected) ->
allPatches[bundle]?.filter { it.name in selected }
?: throw IllegalArgumentException("Patch bundle $bundle does not exist")
}

// Set all patch options.
options.forEach { (bundle, bundlePatchOptions) ->
val patches = allPatches[bundle] ?: return@forEach
val patchesByName = patches.associateBy { it.name }
// Set all patch options.
options.forEach { (bundle, bundlePatchOptions) ->
val patches = allPatches[bundle] ?: return@forEach
val patchesByName = patches.associateBy { it.name }

bundlePatchOptions.forEach { (patchName, configuredPatchOptions) ->
// Morphe: Skip if patch doesn't exist in this bundle
val patch = patchesByName[patchName] ?: return@forEach
bundlePatchOptions.forEach { (patchName, configuredPatchOptions) ->
// Morphe: Skip if patch doesn't exist in this bundle
val patch = patchesByName[patchName] ?: return@forEach

configuredPatchOptions.forEach { (key, value) ->
patch.options[key] = value
configuredPatchOptions.forEach { (key, value) ->
patch.options[key] = value
}
}
}
}

onProgress(null, State.COMPLETED, null) // Loading patches
onProgress(null, State.COMPLETED, null) // Loading patches

val preparation = SplitApkPreparer.prepareIfNeeded(
File(inputFile),
File(cacheDir),
logger,
stripNativeLibs
)
try {
if (preparation.merged) {
onProgress(null, State.COMPLETED, null)
onMergedApkReady?.invoke(preparation.file)
}

Session(
cacheDir,
frameworkPath,
aaptPath,
context,
val preparation = SplitApkPreparer.prepareIfNeeded(
File(inputFile),
File(cacheDir),
logger,
preparation.file,
onPatchCompleted = onPatchCompleted,
onProgress
).use { session ->
session.run(
File(outputFile),
patchList
)
stripNativeLibs
)
try {
if (preparation.merged) {
onProgress(null, State.COMPLETED, null)
onMergedApkReady?.invoke(preparation.file)
}

Session(
cacheDir,
frameworkPath,
context,
logger,
preparation.file,
onPatchCompleted = onPatchCompleted,
onProgress,
bytecodeMode = prefs.bytecodeModePreference.get(),
).use { session ->
session.run(
File(outputFile),
patchList
)
}
} finally {
preparation.cleanup()
}
} finally {
preparation.cleanup()

MemoryMonitor.stopMemoryPolling(logger)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ class ProcessRuntime(
}

val parameters = Parameters(
aaptPath = aaptPath,
frameworkDir = frameworkPath,
cacheDir = cacheDir,
packageName = packageName,
Expand All @@ -276,7 +275,8 @@ class ProcessRuntime(
)
},
stripNativeLibs = stripNativeLibs,
mergedInputFile = mergedInputPath
mergedInputFile = mergedInputPath,
bytecodeMode = prefs.bytecodeModePreference.get(),
)

binder.start(parameters, eventHandler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.content.Context
import app.morphe.manager.data.platform.Filesystem
import app.morphe.manager.domain.manager.PreferencesManager
import app.morphe.manager.domain.repository.PatchBundleRepository
import app.morphe.manager.patcher.aapt.Aapt
import app.morphe.manager.patcher.logger.Logger
import app.morphe.manager.patcher.worker.ProgressEventHandler
import app.morphe.manager.util.Options
Expand All @@ -13,16 +12,13 @@ import kotlinx.coroutines.flow.first
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
import java.io.FileNotFoundException

sealed class Runtime(context: Context) : KoinComponent {
private val fs: Filesystem by inject()
private val patchBundlesRepo: PatchBundleRepository by inject()
protected val prefs: PreferencesManager by inject()

protected val cacheDir: String = fs.tempDir.absolutePath
protected val aaptPath = Aapt.binary(context)?.absolutePath
?: throw FileNotFoundException("Could not resolve aapt.")
protected val frameworkPath: String =
context.cacheDir.resolve("framework").also { it.mkdirs() }.absolutePath

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package app.morphe.manager.patcher.runtime.process

import android.os.Parcelable
import app.morphe.manager.patcher.patch.PatchBundle
import app.morphe.patcher.dex.BytecodeMode
import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.RawValue

@Parcelize
data class Parameters(
val cacheDir: String,
val aaptPath: String,
val frameworkDir: String,
val packageName: String,
val inputFile: String,
Expand All @@ -18,6 +18,7 @@ data class Parameters(
// If non-null, PatcherProcess writes the merged mono-APK to this path after prepareIfNeeded.
// ProcessRuntime reads it back so the main process knows the merged file location.
val mergedInputFile: String? = null,
val bytecodeMode: BytecodeMode,
) : Parcelable

@Parcelize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,15 @@ class PatcherProcess(private val context: Context) : IPatcherProcess.Stub() {

Session(
cacheDir = parameters.cacheDir,
aaptPath = parameters.aaptPath,
frameworkDir = parameters.frameworkDir,
androidContext = context,
logger = logger,
input = preparation.file,
onPatchCompleted = { events.patchSucceeded() },
onProgress = { name, state, message ->
events.progress(name, state?.name, message)
}
},
bytecodeMode = parameters.bytecodeMode,
).use {
it.run(File(parameters.outputFile), patchList)
}
Expand Down
Loading
Loading