Skip to content

Commit e8ac47a

Browse files
authored
Merge pull request #159 from aload0/copilot/delete-old-logs-on-update
Implement log rotation: purge >3d logs on start, clear all on update
2 parents de248f5 + 434eeb4 commit e8ac47a

4 files changed

Lines changed: 96 additions & 13 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@
120120
<action android:name="android.intent.action.BOOT_COMPLETED" />
121121
<category android:name="android.intent.category.DEFAULT" />
122122
</intent-filter>
123+
<intent-filter>
124+
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
125+
</intent-filter>
123126
</receiver>
124127

125128
<provider

app/src/main/java/dev/pranav/applock/AppLockApplication.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import dev.pranav.applock.core.utils.LogUtils
88
import dev.pranav.applock.data.repository.AppLockRepository
99
import org.lsposed.hiddenapibypass.HiddenApiBypass
1010
import rikka.sui.Sui
11+
import kotlin.concurrent.thread
1112

1213
class AppLockApplication : Application() {
1314

@@ -24,6 +25,10 @@ class AppLockApplication : Application() {
2425
initializeComponents()
2526

2627
LogUtils.initialize(this)
28+
// Purge logs older than 3 days on every app start (run in background to avoid ANR)
29+
thread(start = true, name = "LogPurge") {
30+
LogUtils.purgeOldLogs()
31+
}
2732
}
2833

2934
private fun initializeHiddenApiBypass() {

app/src/main/java/dev/pranav/applock/core/broadcast/BootReceiver.kt

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
44
import android.content.Context
55
import android.content.Intent
66
import android.util.Log
7+
import dev.pranav.applock.core.utils.LogUtils
78
import dev.pranav.applock.core.utils.appLockRepository
89
import dev.pranav.applock.data.repository.BackendImplementation
910
import dev.pranav.applock.services.AppLockAccessibilityService
@@ -14,19 +15,24 @@ class BootReceiver : BroadcastReceiver() {
1415

1516
override fun onReceive(context: Context, intent: Intent) {
1617
val repository = context.appLockRepository()
17-
if (intent.action == Intent.ACTION_PACKAGE_REPLACED) {
18-
repository.setShowDonateLink(true)
19-
}
20-
if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
21-
Log.w(TAG, "Invalid context or intent action")
22-
return
23-
}
24-
25-
try {
26-
val appLockRepository = context.appLockRepository()
27-
startAppropriateServices(context, appLockRepository)
28-
} catch (e: Exception) {
29-
Log.e(TAG, "Error starting services on boot", e)
18+
19+
when (intent.action) {
20+
Intent.ACTION_MY_PACKAGE_REPLACED -> {
21+
Log.d(TAG, "App package replaced, clearing old logs and showing donate link")
22+
repository.setShowDonateLink(true)
23+
// Clear all old logs on app update
24+
LogUtils.clearAllLogs()
25+
}
26+
Intent.ACTION_BOOT_COMPLETED -> {
27+
try {
28+
startAppropriateServices(context, repository)
29+
} catch (e: Exception) {
30+
Log.e(TAG, "Error starting services on boot", e)
31+
}
32+
}
33+
else -> {
34+
Log.w(TAG, "Invalid intent action: ${intent.action}")
35+
}
3036
}
3137
}
3238

app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import android.util.Log
88
import androidx.core.content.FileProvider
99
import java.io.File
1010
import java.time.Instant
11+
import java.time.temporal.ChronoUnit
1112

1213
@SuppressLint("StaticFieldLeak")
1314
object LogUtils {
@@ -78,4 +79,72 @@ object LogUtils {
7879
return null
7980
}
8081
}
82+
83+
/**
84+
* Clear all security and audit logs.
85+
* Called when the app is updated.
86+
*/
87+
fun clearAllLogs() {
88+
try {
89+
val securityLogFile = File(context.filesDir, SECURITY_LOGS)
90+
if (securityLogFile.exists()) {
91+
securityLogFile.delete()
92+
Log.d(TAG, "Cleared security logs")
93+
}
94+
95+
val appLogFile = File(context.cacheDir, FILE_NAME)
96+
if (appLogFile.exists()) {
97+
appLogFile.delete()
98+
Log.d(TAG, "Cleared app logs")
99+
}
100+
} catch (e: Exception) {
101+
Log.e(TAG, "Error clearing logs", e)
102+
}
103+
}
104+
105+
/**
106+
* Purge log entries older than 3 days from the audit log file.
107+
* This prevents logs from growing indefinitely.
108+
*/
109+
fun purgeOldLogs() {
110+
try {
111+
val securityLogFile = File(context.filesDir, SECURITY_LOGS)
112+
if (!securityLogFile.exists()) {
113+
return
114+
}
115+
116+
val threeDaysAgo = Instant.now().minus(3, ChronoUnit.DAYS)
117+
val lines = securityLogFile.readLines()
118+
val recentLines = mutableListOf<String>()
119+
120+
for (line in lines) {
121+
try {
122+
// Extract timestamp from log line format: "[ISO-8601 timestamp] D [TAG]: [message]"
123+
val timestampStr = line.substringBefore(" ")
124+
val timestamp = Instant.parse(timestampStr)
125+
126+
if (timestamp.isAfter(threeDaysAgo)) {
127+
recentLines.add(line)
128+
}
129+
} catch (e: Exception) {
130+
// If we can't parse the timestamp, keep the line to avoid data loss
131+
recentLines.add(line)
132+
}
133+
}
134+
135+
// Rewrite the file with only recent logs
136+
if (recentLines.size < lines.size) {
137+
if (recentLines.isEmpty()) {
138+
// Delete the file if no recent logs remain
139+
securityLogFile.delete()
140+
Log.d(TAG, "Deleted log file - all entries were older than 3 days")
141+
} else {
142+
securityLogFile.writeText(recentLines.joinToString("\n") + "\n")
143+
Log.d(TAG, "Purged ${lines.size - recentLines.size} old log entries")
144+
}
145+
}
146+
} catch (e: Exception) {
147+
Log.e(TAG, "Error purging old logs", e)
148+
}
149+
}
81150
}

0 commit comments

Comments
 (0)