mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Fix network logging
Keep some files when packaging apk Improve retreiving security/network logs efficiency
This commit is contained in:
@@ -54,15 +54,6 @@ android {
|
|||||||
compose = true
|
compose = true
|
||||||
aidl = true
|
aidl = true
|
||||||
}
|
}
|
||||||
packaging {
|
|
||||||
resources {
|
|
||||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
||||||
excludes += "/META-INF/**.version"
|
|
||||||
excludes += "kotlin/**"
|
|
||||||
excludes += "**.bin"
|
|
||||||
excludes += "kotlin-tooling-metadata.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
androidResources {
|
androidResources {
|
||||||
generateLocaleConfig = true
|
generateLocaleConfig = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
|||||||
composable(route = "NearbyStreamingPolicy") { NearbyStreamingPolicy(navCtrl) }
|
composable(route = "NearbyStreamingPolicy") { NearbyStreamingPolicy(navCtrl) }
|
||||||
composable(route = "LockTaskMode") { LockTaskMode(navCtrl) }
|
composable(route = "LockTaskMode") { LockTaskMode(navCtrl) }
|
||||||
composable(route = "CACert") { CACert(navCtrl) }
|
composable(route = "CACert") { CACert(navCtrl) }
|
||||||
composable(route = "SecurityLogs") { SecurityLogging(navCtrl) }
|
composable(route = "SecurityLogging") { SecurityLogging(navCtrl) }
|
||||||
composable(route = "DisableAccountManagement") { DisableAccountManagement(navCtrl) }
|
composable(route = "DisableAccountManagement") { DisableAccountManagement(navCtrl) }
|
||||||
composable(route = "SystemUpdatePolicy") { SystemUpdatePolicy(navCtrl) }
|
composable(route = "SystemUpdatePolicy") { SystemUpdatePolicy(navCtrl) }
|
||||||
composable(route = "InstallSystemUpdate") { InstallSystemUpdate(navCtrl) }
|
composable(route = "InstallSystemUpdate") { InstallSystemUpdate(navCtrl) }
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ fun writeClipBoard(context: Context, string: String):Boolean{
|
|||||||
|
|
||||||
lateinit var requestPermission: ActivityResultLauncher<String>
|
lateinit var requestPermission: ActivityResultLauncher<String>
|
||||||
lateinit var exportFile: ActivityResultLauncher<Intent>
|
lateinit var exportFile: ActivityResultLauncher<Intent>
|
||||||
val exportFilePath = MutableStateFlow<String?>(null)
|
var exportFilePath: String? = null
|
||||||
|
var isExportingSecurityOrNetworkLogs = false
|
||||||
|
|
||||||
fun registerActivityResult(context: ComponentActivity){
|
fun registerActivityResult(context: ComponentActivity){
|
||||||
getFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
|
getFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
|
||||||
@@ -87,15 +88,19 @@ fun registerActivityResult(context: ComponentActivity){
|
|||||||
exportFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
exportFile = context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
val intentData = result.data ?: return@registerForActivityResult
|
val intentData = result.data ?: return@registerForActivityResult
|
||||||
val uriData = intentData.data ?: return@registerForActivityResult
|
val uriData = intentData.data ?: return@registerForActivityResult
|
||||||
val path = exportFilePath.value ?: return@registerForActivityResult
|
val path = exportFilePath ?: return@registerForActivityResult
|
||||||
context.contentResolver.openOutputStream(uriData).use { outStream ->
|
context.contentResolver.openOutputStream(uriData).use { outStream ->
|
||||||
if(outStream != null) {
|
if(outStream != null) {
|
||||||
|
if(isExportingSecurityOrNetworkLogs) outStream.write("[".encodeToByteArray())
|
||||||
File(path).inputStream().use { inStream ->
|
File(path).inputStream().use { inStream ->
|
||||||
inStream.copyTo(outStream)
|
inStream.copyTo(outStream)
|
||||||
}
|
}
|
||||||
|
if(isExportingSecurityOrNetworkLogs) outStream.write("]".encodeToByteArray())
|
||||||
Toast.makeText(context.applicationContext, R.string.success, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context.applicationContext, R.string.success, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isExportingSecurityOrNetworkLogs = false
|
||||||
|
exportFilePath = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,24 +32,16 @@ import com.rosan.dhizuku.api.Dhizuku
|
|||||||
import com.rosan.dhizuku.api.Dhizuku.binderWrapper
|
import com.rosan.dhizuku.api.Dhizuku.binderWrapper
|
||||||
import com.rosan.dhizuku.api.DhizukuBinderWrapper
|
import com.rosan.dhizuku.api.DhizukuBinderWrapper
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import kotlinx.serialization.json.addJsonObject
|
import kotlinx.serialization.json.add
|
||||||
import kotlinx.serialization.json.buildJsonArray
|
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
|
||||||
import kotlinx.serialization.json.encodeToStream
|
|
||||||
import kotlinx.serialization.json.jsonArray
|
|
||||||
import kotlinx.serialization.json.put
|
import kotlinx.serialization.json.put
|
||||||
|
import kotlinx.serialization.json.putJsonArray
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import kotlin.io.path.inputStream
|
|
||||||
import kotlin.io.path.notExists
|
|
||||||
import kotlin.io.path.outputStream
|
|
||||||
import kotlin.io.path.writeText
|
|
||||||
|
|
||||||
lateinit var createManagedProfile: ActivityResultLauncher<Intent>
|
lateinit var createManagedProfile: ActivityResultLauncher<Intent>
|
||||||
lateinit var addDeviceAdmin: ActivityResultLauncher<Intent>
|
lateinit var addDeviceAdmin: ActivityResultLauncher<Intent>
|
||||||
@@ -331,73 +323,59 @@ fun permissionList(): List<PermissionItem>{
|
|||||||
@RequiresApi(26)
|
@RequiresApi(26)
|
||||||
fun handleNetworkLogs(context: Context, batchToken: Long) {
|
fun handleNetworkLogs(context: Context, batchToken: Long) {
|
||||||
val networkEvents = context.getDPM().retrieveNetworkLogs(context.getReceiver(), batchToken) ?: return
|
val networkEvents = context.getDPM().retrieveNetworkLogs(context.getReceiver(), batchToken) ?: return
|
||||||
val file = context.filesDir.toPath().resolve("NetworkLogs.json")
|
val file = context.filesDir.resolve("NetworkLogs.json")
|
||||||
if(file.notExists()) file.writeText("[]")
|
val fileExist = file.exists()
|
||||||
val json = Json { ignoreUnknownKeys = true; explicitNulls = false }
|
val json = Json { ignoreUnknownKeys = true; explicitNulls = false }
|
||||||
var events: MutableList<NetworkEventItem>
|
val buffer = file.bufferedWriter()
|
||||||
file.inputStream().use {
|
networkEvents.forEachIndexed { index, event ->
|
||||||
events = json.decodeFromStream(it)
|
if(fileExist && index == 0) buffer.write(",")
|
||||||
}
|
val item = buildJsonObject {
|
||||||
networkEvents.forEach { event ->
|
if(VERSION.SDK_INT >= 28) put("id", event.id)
|
||||||
try {
|
put("time", event.timestamp)
|
||||||
val dnsEvent = event as DnsEvent
|
put("package", event.packageName)
|
||||||
val addresses = mutableListOf<String?>()
|
if(event is DnsEvent) {
|
||||||
dnsEvent.inetAddresses.forEach { inetAddresses ->
|
put("type", "dns")
|
||||||
addresses += inetAddresses.hostAddress
|
put("host", event.hostname)
|
||||||
|
put("count", event.totalResolvedAddressCount)
|
||||||
|
putJsonArray("addresses") {
|
||||||
|
event.inetAddresses.forEach { inetAddresses ->
|
||||||
|
add(inetAddresses.hostAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(event is ConnectEvent) {
|
||||||
|
put("type", "connect")
|
||||||
|
put("address", event.inetAddress.hostAddress)
|
||||||
|
put("port", event.port)
|
||||||
}
|
}
|
||||||
events += NetworkEventItem(
|
|
||||||
id = if(VERSION.SDK_INT >= 28) event.id else null, packageName = event.packageName
|
|
||||||
, timestamp = event.timestamp, type = "dns", hostName = dnsEvent.hostname,
|
|
||||||
hostAddresses = addresses, totalResolvedAddressCount = dnsEvent.totalResolvedAddressCount
|
|
||||||
)
|
|
||||||
} catch(_: Exception) {
|
|
||||||
val connectEvent = event as ConnectEvent
|
|
||||||
events += NetworkEventItem(
|
|
||||||
id = if(VERSION.SDK_INT >= 28) event.id else null, packageName = event.packageName, timestamp = event.timestamp, type = "connect",
|
|
||||||
hostAddress = connectEvent.inetAddress.hostAddress, port = connectEvent.port
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
buffer.write(json.encodeToString(item))
|
||||||
|
if(index < networkEvents.size - 1) buffer.write(",")
|
||||||
}
|
}
|
||||||
file.outputStream().use {
|
buffer.close()
|
||||||
json.encodeToStream(events, it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class NetworkEventItem(
|
|
||||||
val id: Long? = null,
|
|
||||||
@SerialName("package_name") val packageName: String,
|
|
||||||
val timestamp: Long,
|
|
||||||
val type: String,
|
|
||||||
@SerialName("address") val hostAddress: String? = null,
|
|
||||||
val port: Int? = null,
|
|
||||||
@SerialName("host_name") val hostName: String? = null,
|
|
||||||
@SerialName("count") val totalResolvedAddressCount: Int? = null,
|
|
||||||
@SerialName("addresses") val hostAddresses: List<String?>? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
@RequiresApi(24)
|
@RequiresApi(24)
|
||||||
fun handleSecurityLogs(context: Context) {
|
fun handleSecurityLogs(context: Context) {
|
||||||
val file = context.filesDir.resolve("SecurityLogs.json")
|
val file = context.filesDir.resolve("SecurityLogs.json")
|
||||||
val json = Json { ignoreUnknownKeys = true; explicitNulls = false }
|
val json = Json { ignoreUnknownKeys = true; explicitNulls = false }
|
||||||
if(!file.exists()) file.writeText("[]")
|
|
||||||
val securityEvents = context.getDPM().retrieveSecurityLogs(context.getReceiver())
|
val securityEvents = context.getDPM().retrieveSecurityLogs(context.getReceiver())
|
||||||
securityEvents ?: return
|
securityEvents ?: return
|
||||||
val logArray = json.parseToJsonElement(file.readText()).jsonArray
|
val fileExist = file.exists()
|
||||||
val newLogs = buildJsonArray {
|
val buffer = file.bufferedWriter()
|
||||||
securityEvents.forEach { event ->
|
securityEvents.forEachIndexed { index, event ->
|
||||||
addJsonObject {
|
if(fileExist && index == 0) buffer.write(",")
|
||||||
put("time_nanos", event.timeNanos)
|
val item = buildJsonObject {
|
||||||
put("tag", event.tag)
|
put("time_nanos", event.timeNanos)
|
||||||
if(VERSION.SDK_INT >= 28) put("level", event.logLevel)
|
put("tag", event.tag)
|
||||||
if(VERSION.SDK_INT >= 28) put("id", event.id)
|
if(VERSION.SDK_INT >= 28) put("level", event.logLevel)
|
||||||
parseSecurityEventData(event).let { if(it != null) put("data", it) }
|
if(VERSION.SDK_INT >= 28) put("id", event.id)
|
||||||
}
|
parseSecurityEventData(event).let { if(it != null) put("data", it) }
|
||||||
}
|
}
|
||||||
|
buffer.write(json.encodeToString(item))
|
||||||
|
if(index < securityEvents.size - 1) buffer.write(",")
|
||||||
}
|
}
|
||||||
file.outputStream().use {
|
buffer.close()
|
||||||
json.encodeToStream(logArray + newLogs, it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(24)
|
@RequiresApi(24)
|
||||||
@@ -409,7 +387,7 @@ fun parseSecurityEventData(event: SecurityLog.SecurityEvent): JsonElement? {
|
|||||||
val payload = event.data as Array<*>
|
val payload = event.data as Array<*>
|
||||||
buildJsonObject {
|
buildJsonObject {
|
||||||
put("name", payload[0] as String)
|
put("name", payload[0] as String)
|
||||||
put("start_time", payload[1] as Long)
|
put("time", payload[1] as Long)
|
||||||
put("uid", payload[2] as Int)
|
put("uid", payload[2] as Int)
|
||||||
put("pid", payload[3] as Int)
|
put("pid", payload[3] as Int)
|
||||||
put("seinfo", payload[4] as String)
|
put("seinfo", payload[4] as String)
|
||||||
@@ -456,7 +434,7 @@ fun parseSecurityEventData(event: SecurityLog.SecurityEvent): JsonElement? {
|
|||||||
put("admin", payload[0] as String)
|
put("admin", payload[0] as String)
|
||||||
put("admin_user_id", payload[1] as Int)
|
put("admin_user_id", payload[1] as Int)
|
||||||
put("target_user_id", payload[2] as Int)
|
put("target_user_id", payload[2] as Int)
|
||||||
put("feature_mask", payload[3] as Int)
|
put("mask", payload[3] as Int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SecurityLog.TAG_KEYGUARD_DISMISSED -> null
|
SecurityLog.TAG_KEYGUARD_DISMISSED -> null
|
||||||
@@ -521,8 +499,8 @@ fun parseSecurityEventData(event: SecurityLog.SecurityEvent): JsonElement? {
|
|||||||
SecurityLog.TAG_PACKAGE_INSTALLED, SecurityLog.TAG_PACKAGE_UNINSTALLED, SecurityLog.TAG_PACKAGE_UPDATED -> {
|
SecurityLog.TAG_PACKAGE_INSTALLED, SecurityLog.TAG_PACKAGE_UNINSTALLED, SecurityLog.TAG_PACKAGE_UPDATED -> {
|
||||||
val payload = event.data as Array<*>
|
val payload = event.data as Array<*>
|
||||||
buildJsonObject {
|
buildJsonObject {
|
||||||
put("package_name", payload[0] as String)
|
put("name", payload[0] as String)
|
||||||
put("version_code", payload[1] as Long)
|
put("version", payload[1] as Long)
|
||||||
put("user_id", payload[2] as Int)
|
put("user_id", payload[2] as Int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ import com.bintianqi.owndroid.R
|
|||||||
import com.bintianqi.owndroid.exportFile
|
import com.bintianqi.owndroid.exportFile
|
||||||
import com.bintianqi.owndroid.exportFilePath
|
import com.bintianqi.owndroid.exportFilePath
|
||||||
import com.bintianqi.owndroid.formatFileSize
|
import com.bintianqi.owndroid.formatFileSize
|
||||||
|
import com.bintianqi.owndroid.isExportingSecurityOrNetworkLogs
|
||||||
import com.bintianqi.owndroid.selectedPackage
|
import com.bintianqi.owndroid.selectedPackage
|
||||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||||
import com.bintianqi.owndroid.ui.FunctionItem
|
import com.bintianqi.owndroid.ui.FunctionItem
|
||||||
@@ -585,7 +586,8 @@ fun NetworkLogging(navCtrl: NavHostController) {
|
|||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
intent.setType("application/json")
|
intent.setType("application/json")
|
||||||
intent.putExtra(Intent.EXTRA_TITLE, "NetworkLogs.json")
|
intent.putExtra(Intent.EXTRA_TITLE, "NetworkLogs.json")
|
||||||
exportFilePath.value = logFile.path
|
exportFilePath = logFile.path
|
||||||
|
isExportingSecurityOrNetworkLogs = true
|
||||||
exportFile.launch(intent)
|
exportFile.launch(intent)
|
||||||
},
|
},
|
||||||
enabled = fileSize > 0,
|
enabled = fileSize > 0,
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ import com.bintianqi.owndroid.fileUriFlow
|
|||||||
import com.bintianqi.owndroid.formatFileSize
|
import com.bintianqi.owndroid.formatFileSize
|
||||||
import com.bintianqi.owndroid.getFile
|
import com.bintianqi.owndroid.getFile
|
||||||
import com.bintianqi.owndroid.humanReadableDate
|
import com.bintianqi.owndroid.humanReadableDate
|
||||||
|
import com.bintianqi.owndroid.isExportingSecurityOrNetworkLogs
|
||||||
import com.bintianqi.owndroid.prepareForNotification
|
import com.bintianqi.owndroid.prepareForNotification
|
||||||
import com.bintianqi.owndroid.selectedPackage
|
import com.bintianqi.owndroid.selectedPackage
|
||||||
import com.bintianqi.owndroid.toggle
|
import com.bintianqi.owndroid.toggle
|
||||||
@@ -1033,7 +1034,8 @@ fun SecurityLogging(navCtrl: NavHostController) {
|
|||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
intent.setType("application/json")
|
intent.setType("application/json")
|
||||||
intent.putExtra(Intent.EXTRA_TITLE, "SecurityLogs.json")
|
intent.putExtra(Intent.EXTRA_TITLE, "SecurityLogs.json")
|
||||||
exportFilePath.value = logFile.path
|
exportFilePath = logFile.path
|
||||||
|
isExportingSecurityOrNetworkLogs = true
|
||||||
exportFile.launch(intent)
|
exportFile.launch(intent)
|
||||||
},
|
},
|
||||||
enabled = fileSize > 0,
|
enabled = fileSize > 0,
|
||||||
@@ -1081,7 +1083,8 @@ fun SecurityLogging(navCtrl: NavHostController) {
|
|||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
intent.setType("application/json")
|
intent.setType("application/json")
|
||||||
intent.putExtra(Intent.EXTRA_TITLE, "PreRebootSecurityLogs.json")
|
intent.putExtra(Intent.EXTRA_TITLE, "PreRebootSecurityLogs.json")
|
||||||
exportFilePath.value = preRebootSecurityLogs.path
|
exportFilePath = preRebootSecurityLogs.path
|
||||||
|
isExportingSecurityOrNetworkLogs = true
|
||||||
exportFile.launch(intent)
|
exportFile.launch(intent)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user