diff --git a/app/src/main/java/com/dumper/android/dumper/process/Process.kt b/app/src/main/java/com/dumper/android/dumper/process/Process.kt index 7e01e78..96304ba 100644 --- a/app/src/main/java/com/dumper/android/dumper/process/Process.kt +++ b/app/src/main/java/com/dumper/android/dumper/process/Process.kt @@ -7,58 +7,54 @@ import androidx.core.text.isDigitsOnly import com.dumper.android.BuildConfig import com.dumper.android.utils.getApplicationInfoCompact import com.dumper.android.utils.isInvalid +import com.dumper.android.utils.removeNullChar import java.io.File object Process { - fun getAllProcess(ctx: Context, isRoot: Boolean): ArrayList { - val finalAppsBundle = ArrayList() - if (isRoot) { - val activityManager = ctx.getSystemService(ACTIVITY_SERVICE) as ActivityManager + fun getAllProcess(ctx: Context, isRoot: Boolean) = + if (isRoot) + getAllProcessRoot(ctx) + else + getAllProcessNoRoot() - activityManager.runningAppProcesses.forEach { - try { - val apps = ctx.packageManager.getApplicationInfoCompact( - it.processName.substringBefore(":"), 0 - ) - if (!apps.isInvalid() && apps.packageName != BuildConfig.APPLICATION_ID) { - val data = ProcessData( - it.processName, - ctx.packageManager.getApplicationLabel(apps).toString() - ) - finalAppsBundle.add(data) - } - } catch (_: Exception) { - } - } - } else { - val proc = File("/proc") - if (!proc.exists()) - return finalAppsBundle - - val dPID = proc.listFiles() - if (dPID.isNullOrEmpty()) - return finalAppsBundle - for (line in dPID) { - if (!line.name.isDigitsOnly()) - continue; + private fun getAllProcessRoot(ctx: Context): Array { + val activityManager = ctx.getSystemService(ACTIVITY_SERVICE) as ActivityManager + return activityManager.runningAppProcesses + .mapNotNull { + runCatching { + val pkgManager = ctx.packageManager + val app = pkgManager.getApplicationInfoCompact(it.processName, 0) + if (!app.isInvalid() && app.packageName != BuildConfig.APPLICATION_ID) { + val appLabel = pkgManager.getApplicationLabel(app).toString() + ProcessData(it.processName, appLabel) + } else { + null + } + }.getOrNull() + }.toTypedArray() + } - val comm = File("${line.path}/comm") - val cmdline = File("${line.path}/cmdline") + private fun getAllProcessNoRoot(): Array { + return File("/proc") + .listFiles().orEmpty() + .filter { it.name.isDigitsOnly() } + .mapNotNull { + val comm = File("${it.path}/comm") + val cmdline = File("${it.path}/cmdline") if (!comm.exists() || !cmdline.exists()) - continue; + return@mapNotNull null - val processName = comm.readText(Charsets.UTF_8) - val processPkg = cmdline.readText(Charsets.UTF_8) + val processName = comm.readText(Charsets.UTF_8).removeNullChar() + val processPkg = cmdline.readText(Charsets.UTF_8).removeNullChar() if (processPkg != "sh" && !processPkg.contains(BuildConfig.APPLICATION_ID)) { - val data = ProcessData(processPkg, processName) - finalAppsBundle.add(data) + ProcessData(processPkg, processName) + } else { + null } - } - } - return finalAppsBundle + }.toTypedArray() } /** @@ -66,28 +62,16 @@ object Process { * @return pid of process or null if process id is not found */ fun getProcessID(pkg: String): Int? { - val proc = File("/proc") - if (!proc.exists()) - return null - - val dPID = proc.listFiles() - if (dPID.isNullOrEmpty()) - return null - - dPID.find { - if (it.name.isDigitsOnly()) { + return File("/proc") + .listFiles().orEmpty() + .filter { it.name.isDigitsOnly() } + .find { val cmdline = File("${it.path}/cmdline") - if (cmdline.exists()) { - val textCmd = cmdline.readText(Charsets.UTF_8) - if (textCmd.contains(pkg)) { - return@find true - } - } - } - return@find false - }?.let { - return it.name.toInt() - } - return null + if (!cmdline.exists()) + return@find false + + val textCmd = cmdline.readText(Charsets.UTF_8) + return@find textCmd.contains(pkg) + }?.name?.toIntOrNull() } } \ No newline at end of file diff --git a/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt b/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt index cdd55a9..3fa8884 100644 --- a/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt +++ b/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt @@ -2,10 +2,10 @@ package com.dumper.android.messager import android.os.Handler import android.os.Message +import androidx.core.os.BundleCompat import com.dumper.android.core.MainActivity import com.dumper.android.core.RootServices import com.dumper.android.dumper.process.ProcessData -import com.dumper.android.utils.getParcelableArrayListCompact class MSGReceiver(private val activity: MainActivity) : Handler.Callback { @@ -14,7 +14,8 @@ class MSGReceiver(private val activity: MainActivity) : Handler.Callback { when (message.what) { RootServices.MSG_GET_PROCESS_LIST -> { - message.data.getParcelableArrayListCompact(RootServices.LIST_ALL_PROCESS) + BundleCompat.getParcelableArray(message.data, RootServices.LIST_ALL_PROCESS, ProcessData::class.java) + ?.filterIsInstance() ?.let { activity.memory.showProcess(activity, it) } diff --git a/app/src/main/java/com/dumper/android/ui/memory/MemoryViewModel.kt b/app/src/main/java/com/dumper/android/ui/memory/MemoryViewModel.kt index 75ef9da..bfdb436 100644 --- a/app/src/main/java/com/dumper/android/ui/memory/MemoryViewModel.kt +++ b/app/src/main/java/com/dumper/android/ui/memory/MemoryViewModel.kt @@ -1,6 +1,7 @@ package com.dumper.android.ui.memory import android.content.Context +import android.widget.Toast import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.dumper.android.dumper.process.ProcessData @@ -14,25 +15,29 @@ class MemoryViewModel : ViewModel() { val isFixELF = MutableLiveData() val isDumpMetadata = MutableLiveData() - - fun showProcess(ctx: Context, list: ArrayList) { - list.sortBy { it.appName } - - val appNames = list.map { processData -> - val processName = processData.processName - if (processName.contains(":")) - "${processData.appName} (${processName.substringAfter(":")})" - else - processData.appName + fun showProcess(ctx: Context, list: Collection) { + if (list.isEmpty()) { + Toast.makeText(ctx, "No process found", Toast.LENGTH_SHORT).show() + return } + val appNames = list.sortedBy { it.processName } + val appsTitle = appNames + .map { processData -> + val processName = processData.processName + if (processName.contains(":")) + "${processData.appName} (${processName.substringAfter(":")})" + else + processData.appName + }.toTypedArray() + MaterialAlertDialogBuilder(ctx) .setTitle("Select process") - .setSingleChoiceItems(appNames.toTypedArray(), -1) { dialog, which -> - selectedApps.value = list[which].processName + .setSingleChoiceItems(appsTitle, -1 + ) { dialog, idx -> + selectedApps.value = appNames[idx].processName dialog.dismiss() } .show() } - } \ No newline at end of file diff --git a/app/src/main/java/com/dumper/android/utils/Utils.kt b/app/src/main/java/com/dumper/android/utils/Utils.kt index 7631278..d2b1739 100644 --- a/app/src/main/java/com/dumper/android/utils/Utils.kt +++ b/app/src/main/java/com/dumper/android/utils/Utils.kt @@ -14,16 +14,8 @@ fun Long.toHex(): String { } @Suppress("DEPRECATION") -inline fun Bundle.getParcelableArrayListCompact(key: String): ArrayList? { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - getParcelableArrayList(key, T::class.java) - } else { - getParcelableArrayList(key) - } -} - -@Suppress("DEPRECATION") -fun PackageManager.getApplicationInfoCompact(packageName: String, flags: Int): ApplicationInfo { +fun PackageManager.getApplicationInfoCompact(processName: String, flags: Int): ApplicationInfo { + val packageName = processName.substringBefore(":") return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong())) } else {