From 640caf668e7d394e68acfe416e59a5ebaaf422ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:25:55 +0000 Subject: [PATCH 1/5] Initial plan From 372bbd876f3b6fa6afddb2a1d6f6b7afc1d1e76c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:29:40 +0000 Subject: [PATCH 2/5] Implement log management: clear logs on update and purge old logs Co-authored-by: PranavPurwar <75154889+PranavPurwar@users.noreply.github.com> --- .../dev/pranav/applock/AppLockApplication.kt | 30 +++++++++ .../dev/pranav/applock/core/utils/LogUtils.kt | 63 +++++++++++++++++++ .../data/repository/PreferencesRepository.kt | 8 +++ 3 files changed, 101 insertions(+) diff --git a/app/src/main/java/dev/pranav/applock/AppLockApplication.kt b/app/src/main/java/dev/pranav/applock/AppLockApplication.kt index f24b187..fe97363 100644 --- a/app/src/main/java/dev/pranav/applock/AppLockApplication.kt +++ b/app/src/main/java/dev/pranav/applock/AppLockApplication.kt @@ -24,6 +24,7 @@ class AppLockApplication : Application() { initializeComponents() LogUtils.initialize(this) + checkAndHandleAppUpdate() } private fun initializeHiddenApiBypass() { @@ -56,6 +57,35 @@ class AppLockApplication : Application() { } } + /** + * Check if the app has been updated and handle accordingly. + * On update: clear all old logs + * On every start: purge logs older than 3 days + */ + private fun checkAndHandleAppUpdate() { + try { + val prefsRepo = appLockRepository.preferencesRepository + val lastVersionCode = prefsRepo.getLastVersionCode() + val currentVersionCode = BuildConfig.VERSION_CODE + + // Always purge old logs (older than 3 days) on app start + LogUtils.purgeOldLogs() + + // If app was updated, clear all logs and update version code + if (lastVersionCode != 0 && lastVersionCode < currentVersionCode) { + Log.d(TAG, "App updated from version $lastVersionCode to $currentVersionCode. Clearing logs.") + LogUtils.clearAllLogs() + prefsRepo.setLastVersionCode(currentVersionCode) + } else if (lastVersionCode == 0) { + // First time app is running, just save the version code + Log.d(TAG, "First app launch. Setting version code to $currentVersionCode") + prefsRepo.setLastVersionCode(currentVersionCode) + } + } catch (e: Exception) { + Log.e(TAG, "Error checking app update", e) + } + } + companion object { private const val TAG = "AppLockApplication" } diff --git a/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt b/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt index 8592dd2..accf246 100644 --- a/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt +++ b/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt @@ -8,6 +8,7 @@ import android.util.Log import androidx.core.content.FileProvider import java.io.File import java.time.Instant +import java.time.temporal.ChronoUnit @SuppressLint("StaticFieldLeak") object LogUtils { @@ -78,4 +79,66 @@ object LogUtils { return null } } + + /** + * Clear all security and audit logs. + * Called when the app is updated. + */ + fun clearAllLogs() { + try { + val securityLogFile = File(context.filesDir, SECURITY_LOGS) + if (securityLogFile.exists()) { + securityLogFile.delete() + Log.d(TAG, "Cleared security logs") + } + + val appLogFile = File(context.cacheDir, FILE_NAME) + if (appLogFile.exists()) { + appLogFile.delete() + Log.d(TAG, "Cleared app logs") + } + } catch (e: Exception) { + Log.e(TAG, "Error clearing logs", e) + } + } + + /** + * Purge log entries older than 3 days from the audit log file. + * This prevents logs from growing indefinitely. + */ + fun purgeOldLogs() { + try { + val securityLogFile = File(context.filesDir, SECURITY_LOGS) + if (!securityLogFile.exists()) { + return + } + + val threeDaysAgo = Instant.now().minus(3, ChronoUnit.DAYS) + val lines = securityLogFile.readLines() + val recentLines = mutableListOf() + + for (line in lines) { + try { + // Extract timestamp from log line format: "2024-01-15T10:30:00Z D TAG: message" + val timestampStr = line.substringBefore(" ") + val timestamp = Instant.parse(timestampStr) + + if (timestamp.isAfter(threeDaysAgo)) { + recentLines.add(line) + } + } catch (e: Exception) { + // If we can't parse the timestamp, keep the line to avoid data loss + recentLines.add(line) + } + } + + // Rewrite the file with only recent logs + if (recentLines.size < lines.size) { + securityLogFile.writeText(recentLines.joinToString("\n") + "\n") + Log.d(TAG, "Purged ${lines.size - recentLines.size} old log entries") + } + } catch (e: Exception) { + Log.e(TAG, "Error purging old logs", e) + } + } } diff --git a/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt b/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt index 25dc6d7..f7a6c41 100644 --- a/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt +++ b/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt @@ -146,6 +146,14 @@ class PreferencesRepository(context: Context) { settingsPrefs.edit { putBoolean(KEY_SHOW_DONATE_LINK, show) } } + fun getLastVersionCode(): Int { + return settingsPrefs.getInt(LAST_VERSION_CODE, 0) + } + + fun setLastVersionCode(versionCode: Int) { + settingsPrefs.edit { putInt(LAST_VERSION_CODE, versionCode) } + } + companion object { private const val PREFS_NAME_APP_LOCK = "app_lock_prefs" private const val PREFS_NAME_SETTINGS = "app_lock_settings" From 509e2dc19761d2d12a25c8a5a6f2748d91d0fcc7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:31:56 +0000 Subject: [PATCH 3/5] Simplify implementation: reuse package replaced intent for log cleanup Co-authored-by: PranavPurwar <75154889+PranavPurwar@users.noreply.github.com> --- app/src/main/AndroidManifest.xml | 3 ++ .../dev/pranav/applock/AppLockApplication.kt | 32 ++---------------- .../applock/core/broadcast/BootReceiver.kt | 33 +++++++++++-------- .../data/repository/PreferencesRepository.kt | 8 ----- 4 files changed, 25 insertions(+), 51 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 60305a4..1363694 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -120,6 +120,9 @@ + + + { + Log.d(TAG, "App package replaced, clearing old logs and showing donate link") + repository.setShowDonateLink(true) + // Clear all old logs on app update + LogUtils.clearAllLogs() + } + Intent.ACTION_BOOT_COMPLETED -> { + try { + val appLockRepository = context.appLockRepository() + startAppropriateServices(context, appLockRepository) + } catch (e: Exception) { + Log.e(TAG, "Error starting services on boot", e) + } + } + else -> { + Log.w(TAG, "Invalid intent action: ${intent.action}") + } } } diff --git a/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt b/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt index f7a6c41..25dc6d7 100644 --- a/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt +++ b/app/src/main/java/dev/pranav/applock/data/repository/PreferencesRepository.kt @@ -146,14 +146,6 @@ class PreferencesRepository(context: Context) { settingsPrefs.edit { putBoolean(KEY_SHOW_DONATE_LINK, show) } } - fun getLastVersionCode(): Int { - return settingsPrefs.getInt(LAST_VERSION_CODE, 0) - } - - fun setLastVersionCode(versionCode: Int) { - settingsPrefs.edit { putInt(LAST_VERSION_CODE, versionCode) } - } - companion object { private const val PREFS_NAME_APP_LOCK = "app_lock_prefs" private const val PREFS_NAME_SETTINGS = "app_lock_settings" From 171117b3cdf867e63412bd35f7ef91a453cad053 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:32:49 +0000 Subject: [PATCH 4/5] Address code review feedback: run log purge in background thread and handle empty files Co-authored-by: PranavPurwar <75154889+PranavPurwar@users.noreply.github.com> --- .../main/java/dev/pranav/applock/AppLockApplication.kt | 7 +++++-- .../java/dev/pranav/applock/core/utils/LogUtils.kt | 10 ++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/dev/pranav/applock/AppLockApplication.kt b/app/src/main/java/dev/pranav/applock/AppLockApplication.kt index 8a9e47e..9f21a79 100644 --- a/app/src/main/java/dev/pranav/applock/AppLockApplication.kt +++ b/app/src/main/java/dev/pranav/applock/AppLockApplication.kt @@ -8,6 +8,7 @@ import dev.pranav.applock.core.utils.LogUtils import dev.pranav.applock.data.repository.AppLockRepository import org.lsposed.hiddenapibypass.HiddenApiBypass import rikka.sui.Sui +import kotlin.concurrent.thread class AppLockApplication : Application() { @@ -24,8 +25,10 @@ class AppLockApplication : Application() { initializeComponents() LogUtils.initialize(this) - // Purge logs older than 3 days on every app start - LogUtils.purgeOldLogs() + // Purge logs older than 3 days on every app start (run in background to avoid ANR) + thread(start = true, name = "LogPurge") { + LogUtils.purgeOldLogs() + } } private fun initializeHiddenApiBypass() { diff --git a/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt b/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt index accf246..99ad03d 100644 --- a/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt +++ b/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt @@ -134,8 +134,14 @@ object LogUtils { // Rewrite the file with only recent logs if (recentLines.size < lines.size) { - securityLogFile.writeText(recentLines.joinToString("\n") + "\n") - Log.d(TAG, "Purged ${lines.size - recentLines.size} old log entries") + if (recentLines.isEmpty()) { + // Delete the file if no recent logs remain + securityLogFile.delete() + Log.d(TAG, "Deleted log file - all entries were older than 3 days") + } else { + securityLogFile.writeText(recentLines.joinToString("\n") + "\n") + Log.d(TAG, "Purged ${lines.size - recentLines.size} old log entries") + } } } catch (e: Exception) { Log.e(TAG, "Error purging old logs", e) From 434eeb41dce52a4d7db316a9a41457a0f0fc5b2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 16:33:58 +0000 Subject: [PATCH 5/5] Minor code improvements: fix comment and remove shadowed variable Co-authored-by: PranavPurwar <75154889+PranavPurwar@users.noreply.github.com> --- .../java/dev/pranav/applock/core/broadcast/BootReceiver.kt | 3 +-- app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/dev/pranav/applock/core/broadcast/BootReceiver.kt b/app/src/main/java/dev/pranav/applock/core/broadcast/BootReceiver.kt index 4aed6cd..4f04857 100644 --- a/app/src/main/java/dev/pranav/applock/core/broadcast/BootReceiver.kt +++ b/app/src/main/java/dev/pranav/applock/core/broadcast/BootReceiver.kt @@ -25,8 +25,7 @@ class BootReceiver : BroadcastReceiver() { } Intent.ACTION_BOOT_COMPLETED -> { try { - val appLockRepository = context.appLockRepository() - startAppropriateServices(context, appLockRepository) + startAppropriateServices(context, repository) } catch (e: Exception) { Log.e(TAG, "Error starting services on boot", e) } diff --git a/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt b/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt index 99ad03d..7ad5535 100644 --- a/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt +++ b/app/src/main/java/dev/pranav/applock/core/utils/LogUtils.kt @@ -119,7 +119,7 @@ object LogUtils { for (line in lines) { try { - // Extract timestamp from log line format: "2024-01-15T10:30:00Z D TAG: message" + // Extract timestamp from log line format: "[ISO-8601 timestamp] D [TAG]: [message]" val timestampStr = line.substringBefore(" ") val timestamp = Instant.parse(timestampStr)