add MemInfo
This commit is contained in:
parent
d1fa83d15c
commit
a43fcad558
@ -7,7 +7,7 @@ apiVersion = "82"
|
|||||||
datastore = "1.1.7"
|
datastore = "1.1.7"
|
||||||
datastorePreferences = "1.1.7"
|
datastorePreferences = "1.1.7"
|
||||||
googleSymbolProcessingApi = "2.0.0-1.0.24"
|
googleSymbolProcessingApi = "2.0.0-1.0.24"
|
||||||
gson = "2.13.1"
|
gson = "2.13.2"
|
||||||
jsonVersion = "20250517"
|
jsonVersion = "20250517"
|
||||||
kotlin = "2.0.0"
|
kotlin = "2.0.0"
|
||||||
coreKtx = "1.16.0"
|
coreKtx = "1.16.0"
|
||||||
|
|||||||
@ -50,6 +50,8 @@ dependencies {
|
|||||||
implementation(libs.androidx.datastore.preferences)
|
implementation(libs.androidx.datastore.preferences)
|
||||||
// implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.7")
|
// implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.7")
|
||||||
implementation(libs.androidx.datastore)
|
implementation(libs.androidx.datastore)
|
||||||
|
implementation(libs.squareup.okhttp)
|
||||||
|
implementation(libs.gson)
|
||||||
// implementation("androidx.datastore:datastore-rxjava3:1.1.7")
|
// implementation("androidx.datastore:datastore-rxjava3:1.1.7")
|
||||||
implementation("androidx.security:security-state:1.0.0-alpha04")
|
implementation("androidx.security:security-state:1.0.0-alpha04")
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
|
|||||||
@ -35,11 +35,6 @@ class BluetoothInfo(private val context: Context) {
|
|||||||
|
|
||||||
val requiredPermissions: Array<String>
|
val requiredPermissions: Array<String>
|
||||||
get() = buildList {
|
get() = buildList {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
add(Manifest.permission.BLUETOOTH_CONNECT)
|
||||||
add(Manifest.permission.BLUETOOTH_CONNECT)
|
|
||||||
} else {
|
|
||||||
add(Manifest.permission.BLUETOOTH)
|
|
||||||
add(Manifest.permission.BLUETOOTH_ADMIN)
|
|
||||||
}
|
|
||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,141 @@
|
|||||||
package com.xyzshell.andinfo.libs
|
package com.xyzshell.andinfo.libs
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.RandomAccessFile
|
||||||
|
|
||||||
|
data class MemoryInfo(
|
||||||
|
val totalRam: Long, // 总内存 (字节)
|
||||||
|
val availableRam: Long, // 可用内存 (字节)
|
||||||
|
val usedRam: Long, // 已使用内存 (字节)
|
||||||
|
val memType: String, // 内存类型 (LPDDR4/LPDDR5等)
|
||||||
|
val channels: Int, // 内存通道数
|
||||||
|
val zramTotal: Long, // zram 总大小 (字节)
|
||||||
|
val zramUsed: Long // zram 已使用 (字节)
|
||||||
|
)
|
||||||
|
|
||||||
class MemInfo {
|
class MemInfo {
|
||||||
|
|
||||||
|
fun getMemoryInfo(): MemoryInfo {
|
||||||
|
val totalRam = getTotalMemory()
|
||||||
|
val availableRam = getAvailableMemory()
|
||||||
|
val usedRam = totalRam - availableRam
|
||||||
|
val memType = getMemoryType()
|
||||||
|
val channels = getMemoryChannels()
|
||||||
|
val (zramTotal, zramUsed) = getZramInfo()
|
||||||
|
|
||||||
|
return MemoryInfo(
|
||||||
|
totalRam = totalRam,
|
||||||
|
availableRam = availableRam,
|
||||||
|
usedRam = usedRam,
|
||||||
|
memType = memType,
|
||||||
|
channels = channels,
|
||||||
|
zramTotal = zramTotal,
|
||||||
|
zramUsed = zramUsed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTotalMemory(): Long {
|
||||||
|
return try {
|
||||||
|
val memInfo = File("/proc/meminfo")
|
||||||
|
memInfo.readLines().find { it.startsWith("MemTotal:") }?.let {
|
||||||
|
it.split("\\s+".toRegex())[1].toLong() * 1024
|
||||||
|
} ?: 0L
|
||||||
|
} catch (e: Exception) {
|
||||||
|
0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAvailableMemory(): Long {
|
||||||
|
return try {
|
||||||
|
val memInfo = File("/proc/meminfo")
|
||||||
|
memInfo.readLines().find { it.startsWith("MemAvailable:") }?.let {
|
||||||
|
it.split("\\s+".toRegex())[1].toLong() * 1024
|
||||||
|
} ?: 0L
|
||||||
|
} catch (e: Exception) {
|
||||||
|
0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMemoryType(): String {
|
||||||
|
return try {
|
||||||
|
// 尝试从多个可能的位置读取
|
||||||
|
val paths = listOf(
|
||||||
|
"/sys/class/devfreq/ddrfreq/device/type",
|
||||||
|
"/sys/class/devfreq/soc:qcom,cpu-cpu-llcc-bw/device/type",
|
||||||
|
"/proc/device-tree/memory/device_type"
|
||||||
|
)
|
||||||
|
|
||||||
|
for (path in paths) {
|
||||||
|
val file = File(path)
|
||||||
|
if (file.exists()) {
|
||||||
|
val content = file.readText().trim()
|
||||||
|
if (content.isNotEmpty()) {
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试从 getprop 获取
|
||||||
|
Runtime.getRuntime().exec("getprop ro.boot.ddr_type").inputStream.bufferedReader().readText().trim()
|
||||||
|
.ifEmpty { "Unknown" }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"Unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMemoryChannels(): Int {
|
||||||
|
return try {
|
||||||
|
// 尝试从设备树或内核日志获取
|
||||||
|
val dmesgChannels = Runtime.getRuntime()
|
||||||
|
.exec("dmesg | grep -i 'memory.*channel'")
|
||||||
|
.inputStream.bufferedReader().readText()
|
||||||
|
|
||||||
|
// 解析通道数,默认返回 2
|
||||||
|
when {
|
||||||
|
dmesgChannels.contains("dual", ignoreCase = true) -> 2
|
||||||
|
dmesgChannels.contains("quad", ignoreCase = true) -> 4
|
||||||
|
dmesgChannels.contains("single", ignoreCase = true) -> 1
|
||||||
|
else -> 2 // 默认双通道
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getZramInfo(): Pair<Long, Long> {
|
||||||
|
return try {
|
||||||
|
var total = 0L
|
||||||
|
var used = 0L
|
||||||
|
|
||||||
|
// 检查所有 zram 设备
|
||||||
|
for (i in 0..7) {
|
||||||
|
val devicePath = "/sys/block/zram$i"
|
||||||
|
if (!File(devicePath).exists()) continue
|
||||||
|
|
||||||
|
// 读取总大小
|
||||||
|
File("$devicePath/disksize").readText().trim().toLongOrNull()?.let {
|
||||||
|
total += it
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取已使用大小
|
||||||
|
File("$devicePath/mem_used_total").readText().trim().toLongOrNull()?.let {
|
||||||
|
used += it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair(total, used)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Pair(0L, 0L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化内存大小
|
||||||
|
fun formatBytes(bytes: Long): String {
|
||||||
|
return when {
|
||||||
|
bytes < 1024 -> "$bytes B"
|
||||||
|
bytes < 1024 * 1024 -> String.format("%.2f KB", bytes / 1024.0)
|
||||||
|
bytes < 1024 * 1024 * 1024 -> String.format("%.2f MB", bytes / (1024.0 * 1024))
|
||||||
|
else -> String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
package com.xyzshell.andinfo.libs
|
||||||
|
|
||||||
|
class NetworkInfo {
|
||||||
|
}
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package com.xyzshell.andinfo.utils
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import okhttp3.*
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class WebService {
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
val gson = Gson()
|
||||||
|
fun postData(url: String, jsonData: String, callback: (String?, Exception?) -> Unit) {
|
||||||
|
val mediaType = "application/json; charset=utf-8".toMediaType()
|
||||||
|
val body = jsonData.toRequestBody(mediaType)
|
||||||
|
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.post(body)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
client.newCall(request).enqueue(object : Callback {
|
||||||
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
|
callback(null, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResponse(call: Call, response: Response) {
|
||||||
|
response.use {
|
||||||
|
if (it.isSuccessful) {
|
||||||
|
callback(it.body?.string(), null)
|
||||||
|
} else {
|
||||||
|
callback(null, Exception("HTTP ${it.code}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步版本
|
||||||
|
fun postDataSync(url: String, jsonData: String): String? {
|
||||||
|
val mediaType = "application/json; charset=utf-8".toMediaType()
|
||||||
|
val body = jsonData.toRequestBody(mediaType)
|
||||||
|
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.post(body)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
client.newCall(request).execute().use { response ->
|
||||||
|
return if (response.isSuccessful) {
|
||||||
|
response.body?.string()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化对象为 JSON
|
||||||
|
fun <T> toJson(obj: T): String {
|
||||||
|
return gson.toJson(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反序列化 JSON 为对象
|
||||||
|
inline fun <reified T> fromJson(json: String): T? {
|
||||||
|
return try {
|
||||||
|
gson.fromJson(json, T::class.java)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 带序列化的 POST 请求
|
||||||
|
fun <T> postObject(url: String, obj: T, callback: (String?, Exception?) -> Unit) {
|
||||||
|
val jsonData = toJson(obj)
|
||||||
|
postData(url, jsonData, callback)
|
||||||
|
}
|
||||||
|
// 带序列化和反序列化的 POST 请求
|
||||||
|
inline fun <reified T, reified R> postAndParse(
|
||||||
|
url: String,
|
||||||
|
obj: T,
|
||||||
|
crossinline callback: (R?, Exception?) -> Unit
|
||||||
|
) {
|
||||||
|
val jsonData = toJson(obj)
|
||||||
|
postData(url, jsonData) { response, error ->
|
||||||
|
if (error != null) {
|
||||||
|
callback(null, error)
|
||||||
|
} else if (response != null) {
|
||||||
|
val result = fromJson<R>(response)
|
||||||
|
callback(result, null)
|
||||||
|
} else {
|
||||||
|
callback(null, Exception("Empty response"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user