diff --git a/kazeia-android/app/src/main/AndroidManifest.xml b/kazeia-android/app/src/main/AndroidManifest.xml
index 930e896..e2ec260 100644
--- a/kazeia-android/app/src/main/AndroidManifest.xml
+++ b/kazeia-android/app/src/main/AndroidManifest.xml
@@ -9,13 +9,6 @@
-
-
log(msg) }
- MemoryOptimizer.startPeriodicOptimizer(this, serviceScope) { msg -> log(msg) }
initializeComponents()
}
diff --git a/kazeia-android/app/src/main/java/com/kazeia/service/MemoryOptimizer.kt b/kazeia-android/app/src/main/java/com/kazeia/service/MemoryOptimizer.kt
deleted file mode 100644
index 3321f2e..0000000
--- a/kazeia-android/app/src/main/java/com/kazeia/service/MemoryOptimizer.kt
+++ /dev/null
@@ -1,166 +0,0 @@
-package com.kazeia.service
-
-import android.app.ActivityManager
-import android.content.Context
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.currentCoroutineContext
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-
-/**
- * Frees RAM for Kazeia's ML models by nudging non-essential background
- * processes out of memory. Uses `ActivityManager.killBackgroundProcesses`
- * which:
- * - only kills processes that are NOT in foreground or bound to something
- * foreground (so no user-visible disruption),
- * - leaves the package installed/launchable — the OS will respawn it on
- * demand if the user opens the app or a push arrives,
- * - requires only `KILL_BACKGROUND_PROCESSES`, a normal permission.
- *
- * Call [freeRamForModels] once, early in KazeiaService.onCreate, BEFORE
- * loading Qwen3-4B (which needs ~3.2 GB resident to avoid swap thrashing).
- *
- * The list below was picked by reading `dumpsys meminfo` on a fresh boot
- * of a OnePlus Pad 3 (ColorOS 16): every package here is either a Google
- * background feature Kazeia doesn't use (Wallet, Chromecast, YouTube
- * prefetch, …) or an OPLUS feature that re-spawns harmlessly when needed.
- * We deliberately avoid Play Services core, input method, launcher,
- * system_server, systemui, surfaceflinger, audioserver, HAL services —
- * killing any of those would break the UI or audio routing.
- */
-object MemoryOptimizer {
-
- private const val TAG = "MemoryOptimizer"
-
- /** Packages safe to evict. Order matches approximate RAM savings. */
- private val KILL_TARGETS = listOf(
- // Google optional features
- "com.google.android.googlequicksearchbox",
- "com.google.android.youtube",
- "com.google.android.apps.walletnfcrel",
- "com.google.android.apps.chromecast.app",
- "com.google.android.aicore",
- "com.google.android.apps.messaging",
- "com.google.android.apps.tachyon", // Google Meet/Duo (resp. 96 MB)
- "com.google.android.gm",
- "com.google.android.as",
- "com.google.android.as.oss",
- // Additional targets discovered as respawning heavy after the
- // first kill sweep on OnePlus Pad 3 — all user-facing apps that
- // we don't need while Kazeia is the active task.
- "com.google.android.apps.photos",
- "com.google.android.calendar",
- "com.android.providers.calendar",
- "com.google.android.contacts",
- "com.android.vending", // Play Store (resp. 150 MB)
- "com.google.android.rkpdapp",
- "android.process.acore",
- // OPLUS / ColorOS optional features
- "com.oneplus.deskclock",
- "com.coloros.smartsidebar",
- "com.coloros.assistantscreen",
- "com.coloros.weather.service",
- "com.heytap.mcs",
- "com.heytap.accessory",
- "com.oplus.cosa",
- "com.oplus.pantanal.ums",
- "com.oplus.nhs",
- "com.oplus.midas",
- "com.oplus.olc",
- "com.oplus.deepthinker",
- "com.oplus.blur",
- "com.oplus.statistics.rom",
- "com.oplus.powermonitor",
- "com.oplus.romupdate",
- "com.oplus.location",
- "com.oplus.gesture",
- "com.oplus.appplatform",
- "com.oplus.persist.multimedia",
- "com.oplus.nas",
- "com.oplus.notificationmanager",
- "com.oplus.safecenter",
- "com.oplus.securitypermission",
- "com.oplus.sau",
- // Qualcomm workload profiler — perf hints only, respawns
- "com.qualcomm.qti.workloadclassifier"
- )
-
- /**
- * Ask ActivityManager to drop background processes for every package
- * in [KILL_TARGETS] that is installed. Returns a (attempted, skipped)
- * pair for logging. Safe to call from any thread.
- */
- fun freeRamForModels(context: Context, log: (String) -> Unit = {}): Pair {
- val am = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
- ?: run { log("$TAG: ActivityManager unavailable"); return 0 to 0 }
- val pm = context.packageManager
- val memBefore = readAvailMb(am)
-
- var killed = 0
- var skipped = 0
- for (pkg in KILL_TARGETS) {
- try {
- // Only attempt for installed packages — unknown packages
- // would silently no-op but still spam the audit log.
- pm.getPackageInfo(pkg, 0)
- am.killBackgroundProcesses(pkg)
- killed++
- } catch (_: android.content.pm.PackageManager.NameNotFoundException) {
- skipped++
- } catch (e: SecurityException) {
- log("$TAG: killBackgroundProcesses($pkg) denied: ${e.message}")
- skipped++
- } catch (e: Exception) {
- log("$TAG: killBackgroundProcesses($pkg) failed: ${e.message}")
- skipped++
- }
- }
-
- // Give the kernel a moment to reclaim pages before we report.
- Thread.sleep(250)
- val memAfter = readAvailMb(am)
- log("$TAG: killed=$killed skipped=$skipped; avail RAM ${memBefore} MB → ${memAfter} MB (+${memAfter - memBefore} MB)")
- return killed to skipped
- }
-
- private fun readAvailMb(am: ActivityManager): Long {
- val info = ActivityManager.MemoryInfo()
- am.getMemoryInfo(info)
- return info.availMem / (1024 * 1024)
- }
-
- /**
- * Kick off a background coroutine that re-runs [freeRamForModels]
- * every [periodMs]. ColorOS's ActivityManager auto-respawns killed
- * apps within 1–3 minutes (observed: quicksearchbox coming back at
- * 210 MB, photos/calendar/vending spawning fresh), so a single
- * startup sweep isn't enough — periodic pruning is needed while
- * Kazeia holds its models in memory.
- *
- * Cheap (~100 ms total per sweep, mostly the intentional 250 ms
- * settle sleep in freeRamForModels), so 60 s cadence is safe. The
- * returned [kotlinx.coroutines.Job] should be cancelled by the
- * caller when the service stops, to avoid waking the CPU after
- * shutdown.
- */
- fun startPeriodicOptimizer(
- context: Context,
- scope: CoroutineScope,
- periodMs: Long = 60_000L,
- log: (String) -> Unit = {}
- ): Job = scope.launch(Dispatchers.IO) {
- // First run already happened at service onCreate — skip the
- // initial interval so we don't double-sweep on startup.
- delay(periodMs)
- while (currentCoroutineContext()[Job]?.isActive != false) {
- try {
- freeRamForModels(context, log)
- } catch (e: Exception) {
- log("$TAG: periodic sweep failed: ${e.message}")
- }
- delay(periodMs)
- }
- }
-}