Skip to content

Commit

Permalink
Use ParcelableArray in getAllProcess (#21)
Browse files Browse the repository at this point in the history
* Use `ParcelableArray` in `getAllProcess`

* Upgrade androidx.core:core-ktx v1.10.0

* Fix type iteration
  • Loading branch information
BryanGIG authored Oct 26, 2023
1 parent f811f43 commit 0258147
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 84 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ android {

dependencies {
//Ui
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.fragment:fragment-ktx:1.5.5'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.0'
Expand Down
99 changes: 41 additions & 58 deletions app/src/main/java/com/dumper/android/dumper/process/Process.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,83 +12,66 @@ import java.io.File

object Process {

fun getAllProcess(ctx: Context, isRoot: Boolean): ArrayList<ProcessData> {
val finalAppsBundle = ArrayList<ProcessData>()
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)

private fun getAllProcessRoot(ctx: Context): List<ProcessData> {
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
}
} catch (_: Exception) {
}
}.getOrNull()
}
} 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;
}

val comm = File("${line.path}/comm")
val cmdline = File("${line.path}/cmdline")
private fun getAllProcessNoRoot(): List<ProcessData> {
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).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
}

/**
* Get the PID
* @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()
}
}
5 changes: 3 additions & 2 deletions app/src/main/java/com/dumper/android/messager/MSGReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -14,7 +14,8 @@ class MSGReceiver(private val activity: MainActivity) : Handler.Callback {

when (message.what) {
RootServices.MSG_GET_PROCESS_LIST -> {
message.data.getParcelableArrayListCompact<ProcessData>(RootServices.LIST_ALL_PROCESS)
BundleCompat.getParcelableArray(message.data, RootServices.LIST_ALL_PROCESS, ProcessData::class.java)
?.filterIsInstance<ProcessData>()
?.let {
activity.memory.showProcess(activity, it)
}
Expand Down
31 changes: 18 additions & 13 deletions app/src/main/java/com/dumper/android/ui/memory/MemoryViewModel.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,25 +15,29 @@ class MemoryViewModel : ViewModel() {
val isFixELF = MutableLiveData<Boolean>()
val isDumpMetadata = MutableLiveData<Boolean>()


fun showProcess(ctx: Context, list: ArrayList<ProcessData>) {
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: List<ProcessData>) {
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()
}

}
12 changes: 2 additions & 10 deletions app/src/main/java/com/dumper/android/utils/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,8 @@ fun Long.toHex(): String {
}

@Suppress("DEPRECATION")
inline fun <reified T : Parcelable> Bundle.getParcelableArrayListCompact(key: String): ArrayList<T>? {
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 {
Expand Down

0 comments on commit 0258147

Please sign in to comment.