diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ebbb7422..363154d3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -158,6 +158,7 @@ dependencies { implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01") implementation("androidx.viewpager2:viewpager2:1.1.0-beta02") implementation("androidx.activity:activity-ktx:1.8.0-alpha06") + implementation("androidx.startup:startup-runtime:1.1.1") val editorVersion = "0.22.0" //noinspection GradleDependency diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index be0f5575..bbc9c081 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,6 +53,16 @@ android:resource="@xml/file_paths" /> + + + + diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/App.kt b/app/src/main/kotlin/org/cosmicide/rewrite/App.kt index 3e66ad7f..fb55f13c 100644 --- a/app/src/main/kotlin/org/cosmicide/rewrite/App.kt +++ b/app/src/main/kotlin/org/cosmicide/rewrite/App.kt @@ -11,7 +11,6 @@ import android.app.Application import android.app.UiModeManager import android.content.res.Configuration import android.os.Build -import android.os.StrictMode import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.recyclerview.widget.LinearLayoutManager @@ -37,10 +36,13 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifTrue import org.lsposed.hiddenapibypass.HiddenApiBypass import rikka.sui.Sui import java.io.File +import java.io.FileInputStream import java.io.FileNotFoundException +import java.io.InputStream import java.lang.ref.WeakReference +import java.math.BigInteger +import java.security.MessageDigest import java.time.ZonedDateTime -import java.util.concurrent.Executors class App : Application() { @@ -62,39 +64,9 @@ class App : Application() { instance = WeakReference(this) HookManager.context = WeakReference(this) - val externalStorage = getExternalFilesDir(null)!! - - Prefs.init(applicationContext) - FileUtil.init(externalStorage) - setupHooks() loadPlugins() - if (BuildConfig.DEBUG) { - StrictMode.setVmPolicy( - StrictMode.VmPolicy.Builder().apply { - detectLeakedRegistrationObjects() - detectActivityLeaks() - detectContentUriWithoutPermission() - detectFileUriExposure() - detectCleartextNetwork() - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { - penaltyLog() - return@apply - } - permitNonSdkApiUsage() - penaltyListener(Executors.newSingleThreadExecutor()) { violation -> - Log.e("StrictMode", "VM violation", violation) - violation.printStackTrace() - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - detectIncorrectContextUse() - detectUnsafeIntentLaunch() - } - }.build() - ) - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { HiddenApiBypass.addHiddenApiExemptions("L") } @@ -142,9 +114,6 @@ class App : Application() { * Extracts kotlin stdlib and stdlib-common from assets. */ fun extractFiles() { - FileUtil.classpathDir.resolve("kotlin-stdlib-1.8.0.jar").apply { - if (exists()) delete() - } extractAsset( "kotlin-stdlib-1.9.0.jar", FileUtil.classpathDir.resolve("kotlin-stdlib-1.9.0.jar") @@ -156,7 +125,10 @@ class App : Application() { } fun extractAsset(assetName: String, targetFile: File) { - targetFile.exists().ifTrue { return } + if (targetFile.exists() && assetNeedsUpdate(assetName, targetFile)) { + targetFile.delete() + } + try { assets.open(assetName).use { inputStream -> targetFile.outputStream().use { outputStream -> @@ -168,6 +140,25 @@ class App : Application() { } } + fun assetNeedsUpdate(assetName: String, targetFile: File): Boolean { + val assetInputStream = assets.open(assetName) + val targetFileInputStream = FileInputStream(targetFile) + val assetChecksum = calculateChecksum(assetInputStream) + val targetFileChecksum = calculateChecksum(targetFileInputStream) + return assetChecksum != targetFileChecksum + } + + fun calculateChecksum(inputStream: InputStream): String { + val md = MessageDigest.getInstance("SHA-256") + val buffer = ByteArray(8192) + var bytesRead: Int + while (inputStream.read(buffer).also { bytesRead = it } != -1) { + md.update(buffer, 0, bytesRead) + } + val digest = md.digest() + return BigInteger(1, digest).toString(16) + } + fun disableModules() { JavacConfigProvider.disableModules() } @@ -186,7 +177,6 @@ class App : Application() { } private fun setupHooks() { - // Some libraries may call System.exit() to exit the app, which crashes the app. // Currently, only JGit does this. HookManager.registerHook(object : Hook( @@ -223,8 +213,6 @@ class App : Application() { param.result = null } }) - - } override fun onConfigurationChanged(newConfig: Configuration) { diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/startup/DebugInitializer.kt b/app/src/main/kotlin/org/cosmicide/rewrite/startup/DebugInitializer.kt new file mode 100644 index 00000000..e30e83d5 --- /dev/null +++ b/app/src/main/kotlin/org/cosmicide/rewrite/startup/DebugInitializer.kt @@ -0,0 +1,45 @@ +package org.cosmicide.rewrite.startup + +import android.content.Context +import android.os.Build +import android.os.StrictMode +import android.util.Log +import androidx.startup.Initializer +import org.cosmicide.rewrite.BuildConfig +import java.util.concurrent.Executors + +class DebugInitializer : Initializer { + + override fun create(context: Context) { + if (BuildConfig.DEBUG) { + enableStrictMode() + } + } + + override fun dependencies(): List>> = emptyList() + + private fun enableStrictMode() { + StrictMode.setVmPolicy( + StrictMode.VmPolicy.Builder().apply { + detectLeakedRegistrationObjects() + detectActivityLeaks() + detectContentUriWithoutPermission() + detectFileUriExposure() + detectCleartextNetwork() + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + penaltyLog() + return@apply + } + permitNonSdkApiUsage() + penaltyListener(Executors.newSingleThreadExecutor()) { violation -> + Log.e("StrictMode", "VM violation", violation) + violation.printStackTrace() + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + detectIncorrectContextUse() + detectUnsafeIntentLaunch() + } + }.build() + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/startup/MainInitializer.kt b/app/src/main/kotlin/org/cosmicide/rewrite/startup/MainInitializer.kt new file mode 100644 index 00000000..d0b95ccc --- /dev/null +++ b/app/src/main/kotlin/org/cosmicide/rewrite/startup/MainInitializer.kt @@ -0,0 +1,16 @@ +package org.cosmicide.rewrite.startup + +import android.content.Context +import androidx.startup.Initializer + +class MainInitializer : Initializer { + + override fun create(context: Context) {} + + override fun dependencies(): List>> { + return listOf( + DebugInitializer::class.java, + PreferencesInitializer::class.java + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/cosmicide/rewrite/startup/PreferencesInitializer.kt b/app/src/main/kotlin/org/cosmicide/rewrite/startup/PreferencesInitializer.kt new file mode 100644 index 00000000..751f8e17 --- /dev/null +++ b/app/src/main/kotlin/org/cosmicide/rewrite/startup/PreferencesInitializer.kt @@ -0,0 +1,16 @@ +package org.cosmicide.rewrite.startup + +import android.content.Context +import androidx.startup.Initializer +import org.cosmicide.rewrite.common.Prefs +import org.cosmicide.rewrite.util.FileUtil + +class PreferencesInitializer : Initializer { + + override fun create(context: Context) { + FileUtil.init(context.getExternalFilesDir(null)!!) + Prefs.init(context.applicationContext) + } + + override fun dependencies(): List>> = emptyList() +} \ No newline at end of file