From 94309a0e9aef7ceb022e554274a95aecc3363b7d Mon Sep 17 00:00:00 2001 From: hg42 Date: Tue, 6 Feb 2024 16:23:11 +0100 Subject: [PATCH 1/7] add paranoidBackupLists + paranoidHousekeeping, otherwise avoid scanning for addBackup etc., rename addBackup to addNewBackup --- .../backup/actions/BackupAppAction.kt | 19 +----- .../machiav3lli/backup/dbs/entity/Backup.kt | 21 ++++--- .../backup/handler/BackupBuilder.kt | 58 +++++++++++++------ .../backup/handler/BackupRestoreHelper.kt | 4 +- .../com/machiav3lli/backup/items/Package.kt | 44 +++++++------- .../backup/preferences/AdvancedPreferences.kt | 13 +++++ .../backup/preferences/ui/PrefsGroup.kt | 4 +- 7 files changed, 98 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/com/machiav3lli/backup/actions/BackupAppAction.kt b/app/src/main/java/com/machiav3lli/backup/actions/BackupAppAction.kt index 08b4e00650..25dfcdd87d 100644 --- a/app/src/main/java/com/machiav3lli/backup/actions/BackupAppAction.kt +++ b/app/src/main/java/com/machiav3lli/backup/actions/BackupAppAction.kt @@ -39,7 +39,6 @@ import com.machiav3lli.backup.items.ActionResult import com.machiav3lli.backup.items.Package import com.machiav3lli.backup.items.RootFile import com.machiav3lli.backup.items.StorageFile -import com.machiav3lli.backup.items.UndeterminedStorageFile import com.machiav3lli.backup.preferences.pref_backupPauseApps import com.machiav3lli.backup.preferences.pref_backupTarCmd import com.machiav3lli.backup.preferences.pref_excludeCache @@ -139,7 +138,7 @@ open class BackupAppAction(context: Context, work: AppActionWork?, shell: ShellH val iv = initIv(CIPHER_ALGORITHM) // as we're using a static Cipher Algorithm backupBuilder.setIv(iv) - val backupInstanceDir = backupBuilder.backupPath + val backupInstanceDir = backupBuilder.backupDir val pauseApp = pref_backupPauseApps.value if (pauseApp) { Timber.d("pre-process package (to avoid file inconsistencies during backup etc.)") @@ -204,7 +203,7 @@ open class BackupAppAction(context: Context, work: AppActionWork?, shell: ShellH backup = backupBuilder.createBackup() - ok = saveBackupProperties(backupBuilder.backupPropsFile, backup) + ok = backup.file != null } catch (e: BackupFailedException) { return handleException(e) @@ -224,7 +223,7 @@ open class BackupAppAction(context: Context, work: AppActionWork?, shell: ShellH backup = backupBuilder.createBackup() // TODO maybe need to handle some emergent props if (ok) - app.addBackup(backup) + app.addNewBackup(backup) else { Timber.d("Backup failed -> deleting it") app.deleteBackup(backup) @@ -237,18 +236,6 @@ open class BackupAppAction(context: Context, work: AppActionWork?, shell: ShellH return ActionResult(app, backup, "", true) } - @Throws(IOException::class) - protected fun saveBackupProperties( - propertiesFile: UndeterminedStorageFile, - backup: Backup, - ): Boolean { - propertiesFile.writeText(backup.toSerialized())?.let { - Timber.i("Wrote $it for backup: $backup") - return true - } - return false - } - @Throws(IOException::class, CryptoSetupException::class) protected fun createBackupArchiveTarApi( backupInstanceDir: StorageFile, diff --git a/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt b/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt index dfb5959538..1a8391efbb 100644 --- a/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt +++ b/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt @@ -275,14 +275,21 @@ data class Backup @OptIn(ExperimentalSerializationApi::class) constructor( @Transient var file: StorageFile? = null - val dir: StorageFile? - get() = if (file?.name == BACKUP_INSTANCE_PROPERTIES_INDIR) { - file?.parent - } else { - val baseName = file?.name?.removeSuffix(".$PROP_NAME") - baseName?.let { dirName -> - file?.parent?.findFile(dirName) + @Ignore + @Transient + var dir: StorageFile? = null + get() { + if (field == null) { + field = if (file?.name == BACKUP_INSTANCE_PROPERTIES_INDIR) { + file?.parent + } else { + val baseName = file?.name?.removeSuffix(".$PROP_NAME") + baseName?.let { dirName -> + file?.parent?.findFile(dirName) + } + } } + return field } val tag: String diff --git a/app/src/main/java/com/machiav3lli/backup/handler/BackupBuilder.kt b/app/src/main/java/com/machiav3lli/backup/handler/BackupBuilder.kt index 166da962a9..a22c843745 100644 --- a/app/src/main/java/com/machiav3lli/backup/handler/BackupBuilder.kt +++ b/app/src/main/java/com/machiav3lli/backup/handler/BackupBuilder.kt @@ -31,6 +31,8 @@ import com.machiav3lli.backup.items.StorageFile import com.machiav3lli.backup.items.UndeterminedStorageFile import com.machiav3lli.backup.preferences.pref_flatStructure import com.machiav3lli.backup.preferences.pref_propertiesInDir +import timber.log.Timber +import java.io.IOException import java.time.LocalDateTime class BackupBuilder( @@ -49,7 +51,7 @@ class BackupBuilder( private var cipherType: String? = null private val cpuArch: String = Build.SUPPORTED_ABIS[0] private var size: Long = 0L - val backupPath = ensureBackupPath(backupRoot) + val backupDir = ensureBackupPath(backupRoot) val backupPropsFile = getPropsFile(backupRoot) private fun ensureBackupPath(backupRoot: StorageFile): StorageFile { @@ -75,14 +77,16 @@ class BackupBuilder( when { pref_propertiesInDir.value -> return UndeterminedStorageFile( - backupPath, + backupDir, BACKUP_INSTANCE_PROPERTIES_INDIR ) + pref_flatStructure.value -> return UndeterminedStorageFile( backupRoot, backupInstancePropsFlat(packageInfo, dateTimeStr) ) + else -> return UndeterminedStorageFile( backupRoot, @@ -131,24 +135,40 @@ class BackupBuilder( this.size = size } + @Throws(IOException::class) + protected fun saveBackupProperties( + propertiesFile: UndeterminedStorageFile, + backup: Backup, + ): StorageFile? { + propertiesFile.writeText(backup.toSerialized())?.let { + Timber.i("Wrote $it for backup: $backup") + return it + } + return null + } + fun createBackup(): Backup { - return Backup( - base = packageInfo, - backupDate = backupDate, - hasApk = hasApk, - hasAppData = hasAppData, - hasDevicesProtectedData = hasDevicesProtectedData, - hasExternalData = hasExternalData, - hasObbData = hasObbData, - hasMediaData = hasMediaData, - compressionType = compressionType, - cipherType = cipherType, - iv = iv, - cpuArch = cpuArch, - permissions = if (packageInfo is AppInfo) packageInfo.permissions else emptyList(), - size = size, - persistent = false, - ) + val backup = + Backup( + base = packageInfo, + backupDate = backupDate, + hasApk = hasApk, + hasAppData = hasAppData, + hasDevicesProtectedData = hasDevicesProtectedData, + hasExternalData = hasExternalData, + hasObbData = hasObbData, + hasMediaData = hasMediaData, + compressionType = compressionType, + cipherType = cipherType, + iv = iv, + cpuArch = cpuArch, + permissions = if (packageInfo is AppInfo) packageInfo.permissions else emptyList(), + size = size, + persistent = false, + ) + backup.dir = backupDir + backup.file = saveBackupProperties(backupPropsFile, backup) + return backup } /*fun createBackupProperties(): BackupProperties { diff --git a/app/src/main/java/com/machiav3lli/backup/handler/BackupRestoreHelper.kt b/app/src/main/java/com/machiav3lli/backup/handler/BackupRestoreHelper.kt index d8b2b5b7f0..41c333270f 100644 --- a/app/src/main/java/com/machiav3lli/backup/handler/BackupRestoreHelper.kt +++ b/app/src/main/java/com/machiav3lli/backup/handler/BackupRestoreHelper.kt @@ -33,6 +33,7 @@ import com.machiav3lli.backup.items.ActionResult import com.machiav3lli.backup.items.Package import com.machiav3lli.backup.items.StorageFile.Companion.invalidateCache import com.machiav3lli.backup.preferences.pref_numBackupRevisions +import com.machiav3lli.backup.preferences.pref_paranoidHousekeeping import com.machiav3lli.backup.tasks.AppActionWork import com.machiav3lli.backup.utils.FileUtils.BackupLocationInAccessibleException import com.machiav3lli.backup.utils.StorageLocationNotConfiguredException @@ -140,7 +141,8 @@ object BackupRestoreHelper { fun housekeepingPackageBackups(app: Package) { - app.refreshBackupList() + if (pref_paranoidHousekeeping.value) + app.refreshBackupList() val numBackupRevisions = pref_numBackupRevisions.value diff --git a/app/src/main/java/com/machiav3lli/backup/items/Package.kt b/app/src/main/java/com/machiav3lli/backup/items/Package.kt index 04f8be330a..8aa6231305 100644 --- a/app/src/main/java/com/machiav3lli/backup/items/Package.kt +++ b/app/src/main/java/com/machiav3lli/backup/items/Package.kt @@ -30,6 +30,7 @@ import com.machiav3lli.backup.handler.findBackups import com.machiav3lli.backup.handler.getPackageStorageStats import com.machiav3lli.backup.preferences.pref_flatStructure import com.machiav3lli.backup.preferences.pref_ignoreLockedInHousekeeping +import com.machiav3lli.backup.preferences.pref_paranoidBackupLists import com.machiav3lli.backup.traceBackups import com.machiav3lli.backup.utils.FileUtils import com.machiav3lli.backup.utils.StorageLocationNotConfiguredException @@ -84,6 +85,7 @@ class Package { refreshStorageStats(context) } + // updateDataOf, NOLABEL (= packageName not found) constructor( context: Context, packageName: String, @@ -221,12 +223,12 @@ class Package { } } - fun addBackup(backup: Backup) { + fun addNewBackup(backup: Backup) { traceBackups { "<${backup.packageName}> add backup ${backup.backupDate}" } - //TODO hg42 update... is not enough, file/dir/tag is only set by creating backup from the file - // file/dir/tag could be added by the caller - // don't do that: updateBackupListAndDatabase(backupList + backup) - refreshBackupList() // or real state of file system + if (pref_paranoidBackupLists.value) + refreshBackupList() // no more necessary, because members file/dir/tag are set by createBackup + else + updateBackupListAndDatabase(backupList + backup) } private fun _deleteBackup(backup: Backup) { @@ -245,16 +247,18 @@ class Package { // ignore } } - //runChecked { - // updateBackupListAndDatabase(backupList - backup) // prevents reading file system - //} + if (pref_paranoidBackupLists.value.not()) + runChecked { + updateBackupListAndDatabase(backupList - backup) // prevents reading file system + } } fun deleteBackup(backup: Backup) { _deleteBackup(backup) - runChecked { - refreshBackupList() // get real state of file system - } + if (pref_paranoidBackupLists.value) + runChecked { + refreshBackupList() // get real state of file system + } } fun rewriteBackup( @@ -274,24 +278,24 @@ class Package { writeText(changedBackup.toSerialized()) } } - runChecked { - //updateBackupListAndDatabase(backupList - backup + changedBackup) - refreshBackupList() - } + if (pref_paranoidBackupLists.value) + runChecked { + refreshBackupList() // get real state of file system + } + //else updateBackupListAndDatabase(backupList - backup + changedBackup) // done in _deleteBackup } fun deleteAllBackups() { val backups = backupsNewestFirst.toMutableList() while (backups.isNotEmpty()) _deleteBackup(backups.removeLast()) - runChecked { - refreshBackupList() // get real state of file system - } + if (pref_paranoidBackupLists.value) + runChecked { + refreshBackupList() // get real state of file system only once + } } fun deleteOldestBackups(keep: Int) { - //refreshBackupList() // should usually be up to date, not dramatic if not - // the algorithm could eventually be more elegant, without managing two lists, // but it's on the safe side for now val backups = backupsNewestFirst.toMutableList() diff --git a/app/src/main/java/com/machiav3lli/backup/preferences/AdvancedPreferences.kt b/app/src/main/java/com/machiav3lli/backup/preferences/AdvancedPreferences.kt index e6adf08fa1..f803a4c364 100644 --- a/app/src/main/java/com/machiav3lli/backup/preferences/AdvancedPreferences.kt +++ b/app/src/main/java/com/machiav3lli/backup/preferences/AdvancedPreferences.kt @@ -289,6 +289,7 @@ val pref_cacheFileLists = BooleanPref( defaultValue = true ) + //---------------------------------------- developer settings - workarounds val pref_fixNavBarOverlap = IntPref( @@ -314,6 +315,18 @@ val pref_refreshAppInfoTimeout = IntPref( //---------------------------------------- developer settings - implementation alternatives +val pref_paranoidBackupLists = BooleanPref( + key = "dev-alt.paranoidBackupLists", + summary = "verify file system after adding or deleting backups (slower, especially remote)", + defaultValue = false +) + +val pref_paranoidHousekeeping = BooleanPref( + key = "dev-alt.paranoidHousekeeping", + summary = "verify file system before housekeeping (slower, especially remote)", + defaultValue = false +) + val pref_ignoreLockedInHousekeeping = BooleanPref( key = "dev-alt.ignoreLockedInHousekeeping", summary = "keep the configured number of unlocked backups, instead of also counting locked backups", diff --git a/app/src/main/java/com/machiav3lli/backup/preferences/ui/PrefsGroup.kt b/app/src/main/java/com/machiav3lli/backup/preferences/ui/PrefsGroup.kt index 39387e260e..baa0333964 100644 --- a/app/src/main/java/com/machiav3lli/backup/preferences/ui/PrefsGroup.kt +++ b/app/src/main/java/com/machiav3lli/backup/preferences/ui/PrefsGroup.kt @@ -18,7 +18,7 @@ import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.requiredWidth import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -152,7 +152,7 @@ fun PrefsExpandableGroupHeader( icon: ImageVector, onClick: (() -> Unit), ) { - Divider(thickness = 2.dp) + HorizontalDivider(thickness = 2.dp) Spacer(modifier = Modifier.height(8.dp)) Card( modifier = modifier From 47c85458648d78f9c3492130de6e74cdf2f2b532 Mon Sep 17 00:00:00 2001 From: hg42 Date: Sun, 11 Feb 2024 18:53:23 +0100 Subject: [PATCH 2/7] fix equality problems (may need a more general solution) --- .../machiav3lli/backup/dbs/entity/Backup.kt | 15 ++++---- .../com/machiav3lli/backup/items/Package.kt | 36 +++++++++++++++---- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt b/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt index 1a8391efbb..75308ad11b 100644 --- a/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt +++ b/app/src/main/java/com/machiav3lli/backup/dbs/entity/Backup.kt @@ -182,29 +182,31 @@ data class Backup @OptIn(ExperimentalSerializationApi::class) constructor( ) override fun toString(): String = "Backup{" + - "backupDate=" + backupDate + + "packageName=" + packageName + + ", backupDate=" + backupDate + ", hasApk=" + hasApk + ", hasAppData=" + hasAppData + ", hasDevicesProtectedData=" + hasDevicesProtectedData + ", hasExternalData=" + hasExternalData + ", hasObbData=" + hasObbData + ", hasMediaData=" + hasMediaData + + ", persistent='" + persistent + '\'' + + ", size=" + size + + ", backupVersionCode='" + backupVersionCode + '\'' + + ", cpuArch='" + cpuArch + '\'' + ", compressionType='" + compressionType + '\'' + ", cipherType='" + cipherType + '\'' + ", iv='" + iv + '\'' + - ", cpuArch='" + cpuArch + '\'' + - ", backupVersionCode='" + backupVersionCode + '\'' + - ", size=" + size + ", permissions='" + permissions + '\'' + - ", persistent='" + persistent + '\'' + '}' override fun equals(other: Any?): Boolean = when { this === other -> true javaClass != other?.javaClass || other !is Backup - || backupVersionCode != other.backupVersionCode || packageName != other.packageName + || backupDate != other.backupDate + || backupVersionCode != other.backupVersionCode || packageLabel != other.packageLabel || versionName != other.versionName || versionCode != other.versionCode @@ -212,7 +214,6 @@ data class Backup @OptIn(ExperimentalSerializationApi::class) constructor( || sourceDir != other.sourceDir || !splitSourceDirs.contentEquals(other.splitSourceDirs) || isSystem != other.isSystem - || backupDate != other.backupDate || hasApk != other.hasApk || hasAppData != other.hasAppData || hasDevicesProtectedData != other.hasDevicesProtectedData diff --git a/app/src/main/java/com/machiav3lli/backup/items/Package.kt b/app/src/main/java/com/machiav3lli/backup/items/Package.kt index 8aa6231305..e70faf1949 100644 --- a/app/src/main/java/com/machiav3lli/backup/items/Package.kt +++ b/app/src/main/java/com/machiav3lli/backup/items/Package.kt @@ -223,12 +223,28 @@ class Package { } } + fun removeBackupFromList(backup: Backup): List { + backupList = backupList.filterNot { + it.packageName == backup.packageName + && it.backupDate == backup.backupDate + } + return backupList + } + + fun addBackupToList(backup: Backup): List { + backupList = backupList + backup + return backupList + } + fun addNewBackup(backup: Backup) { traceBackups { "<${backup.packageName}> add backup ${backup.backupDate}" } if (pref_paranoidBackupLists.value) refreshBackupList() // no more necessary, because members file/dir/tag are set by createBackup - else - updateBackupListAndDatabase(backupList + backup) + else { + //backupList = backupList + changedBackup + addBackupToList(backup) + updateBackupListAndDatabase(backupList) + } } private fun _deleteBackup(backup: Backup) { @@ -247,9 +263,11 @@ class Package { // ignore } } - if (pref_paranoidBackupLists.value.not()) + if (!pref_paranoidBackupLists.value) runChecked { - updateBackupListAndDatabase(backupList - backup) // prevents reading file system + //backupList = backupList - backup + removeBackupFromList(backup) + updateBackupListAndDatabase(backupList) } } @@ -266,7 +284,8 @@ class Package { changedBackup: Backup, ) { //TODO hg42 change to rewriteBackup(backup: Backup, applyParameters) traceBackups { "<${changedBackup.packageName}> rewrite backup ${changedBackup.backupDate}" } - changedBackup.file = backup.file + if (changedBackup.dir == null) changedBackup.dir = backup.dir + if (changedBackup.file == null) changedBackup.file = backup.file if (changedBackup.packageName != packageName) { //TODO hg42 probably paranoid throw RuntimeException("Asked to rewrite a backup of ${changedBackup.packageName} but this object is for $packageName") } @@ -282,7 +301,12 @@ class Package { runChecked { refreshBackupList() // get real state of file system } - //else updateBackupListAndDatabase(backupList - backup + changedBackup) // done in _deleteBackup + else { + //backupList = backupList - backup + changedBackup + removeBackupFromList(backup) + addBackupToList(changedBackup) + updateBackupListAndDatabase(backupList) + } } fun deleteAllBackups() { From 3c077c5b9f913b019b0174ffc9ba47a7710d0a18 Mon Sep 17 00:00:00 2001 From: hg42 Date: Sun, 11 Feb 2024 19:42:45 +0100 Subject: [PATCH 3/7] writeText needs synchronized to prevent duplicate (numbered) files --- app/src/main/java/com/machiav3lli/backup/items/Package.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/machiav3lli/backup/items/Package.kt b/app/src/main/java/com/machiav3lli/backup/items/Package.kt index e70faf1949..498ff2f0d3 100644 --- a/app/src/main/java/com/machiav3lli/backup/items/Package.kt +++ b/app/src/main/java/com/machiav3lli/backup/items/Package.kt @@ -293,8 +293,10 @@ class Package { throw RuntimeException("Asked to rewrite a backup from ${changedBackup.backupDate} but the original backup is from ${backup.backupDate}") } runChecked { - backup.file?.apply { - writeText(changedBackup.toSerialized()) + synchronized(this) { + backup.file?.apply { + writeText(changedBackup.toSerialized()) + } } } if (pref_paranoidBackupLists.value) From f9074a81a696ed6fc8277dce157a04195ca4d422 Mon Sep 17 00:00:00 2001 From: hg42 Date: Thu, 8 Feb 2024 18:19:33 +0100 Subject: [PATCH 4/7] fix version indentation --- .../com/machiav3lli/backup/ui/compose/recycler/Components.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/machiav3lli/backup/ui/compose/recycler/Components.kt b/app/src/main/java/com/machiav3lli/backup/ui/compose/recycler/Components.kt index 664af37ba3..dec729d7c6 100644 --- a/app/src/main/java/com/machiav3lli/backup/ui/compose/recycler/Components.kt +++ b/app/src/main/java/com/machiav3lli/backup/ui/compose/recycler/Components.kt @@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn @@ -415,8 +414,7 @@ fun BusyBackground( color = MaterialTheme.colorScheme.onSurface.copy(alpha = pref_versionOpacity.value / 100f), modifier = Modifier .fillMaxSize() - .wrapContentSize(Alignment.TopStart) - .padding(16.dp, 0.dp, 0.dp, 0.dp) + .wrapContentSize(Alignment.TopCenter) ) } } From 48e52008225896c96349bc6256b492afd24e9c07 Mon Sep 17 00:00:00 2001 From: hg42 Date: Mon, 12 Feb 2024 21:40:24 +0100 Subject: [PATCH 5/7] add test script to show which pids would be stopped by pauseApps --- etc/test-package-pids.sh | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 etc/test-package-pids.sh diff --git a/etc/test-package-pids.sh b/etc/test-package-pids.sh new file mode 100644 index 0000000000..41ac5de410 --- /dev/null +++ b/etc/test-package-pids.sh @@ -0,0 +1,102 @@ +#!/system/bin/sh + + +utilbox=toybox + +suspend=false + +while [[ $1 == --* ]]; do + + if [[ $1 == --suspend ]]; then + shift + suspend=true + continue + fi + + break + +done + +if [[ -z $1 ]]; then + if [[ -n $ANDROID_ROOT ]]; then + packages=$(pm list packages -3 -e | sort | sed s/package://) + cat $0 | bash -s $(echo $packages) 2>/dev/null + else + # remote testing via adb + ( + #echo "packages='\ + # com.google.android.apps.tachyon \ + # com.google.android.gm \ + # com.google.android.inputmethod.latin \ + # com.google.ar.core \ + # com.inspiredandroid.linuxcontrolcenterpro \ + # com.justtradenative \ + # com.kiwibrowser.browser \ + # com.noinnion.android.greader.readerpro \ + # com.whatsapp \ + # de.ralphsapps.snorecontrol \ + # fr.mathis.invisiblewidget \ + # io.github.forkmaintainers.iceraven \ + # jp.co.korg.kaossilator.android \ + # me.zhanghai.android.files \ + # net.cozic.joplin \ + # org.forkclient.messenger.beta \ + # org.kde.kdeconnect_tp \ + # org.mmin.handycalc \ + # '" + echo 'packages=$(pm list packages -3 -e | sort | sed s/package://)' + echo 'bash -s $(echo $packages)' + cat test-package-pids.sh + ) | adb shell su + exit + fi +fi + +while [[ -n $1 ]]; do + + package=$1 + shift + + echo "-- $package" + + #userid=$1 + #shift + + #pm list packages -3 -e -U $package | sed s/package:// | sed s/uid:// | head -n 1 | read pkg userid + read pkg userid < <(pm list packages -U $package | sed s/package:// | sed s/uid:// | head -n 1) #| read pkg userid + #echo p=$pkg u=$userid + if [[ -z $userid ]]; then echo "--- pkg $pkg user $userid"; continue; fi + + #am force-stop $package + #am kill $package + + if $suspend; then + pm suspend $package >/dev/null + $utilbox sleep 3 + fi + + pids=$( + ( + $utilbox ps -A -o PID -u $userid | $utilbox tail -n +2 + $utilbox ls -l /proc/*/fd/* 2>/dev/null | + $utilbox grep -E "/data/data/|/media/" | + #$utilbox grep -E "/data/|/media/" | #TODO add an option for wider catching + $utilbox grep -F /$package/ | + $utilbox cut -s -d / -f 3 + ) | + $utilbox sort -u -n + ) + + #echo "pids=( $pids )" + + if [[ -n $pids ]]; then + $utilbox ps -A -w -o USER,PID,NAME -p $pids | + while read -r user pid process; do + if [[ $user != u0_* ]]; then continue; fi + if [[ $process == android.process.media ]]; then continue; fi + if [[ $process == com.android.externalstorage ]]; then continue; fi + $utilbox echo $process $pid $user + done + fi + +done From 52ff16cd8721351874cc4a9df6c7ab3b130c9154 Mon Sep 17 00:00:00 2001 From: hg42 Date: Sun, 25 Feb 2024 04:15:04 +0100 Subject: [PATCH 6/7] use text/plain to share instead of text/* --- app/src/main/java/com/machiav3lli/backup/utils/SystemUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/machiav3lli/backup/utils/SystemUtils.kt b/app/src/main/java/com/machiav3lli/backup/utils/SystemUtils.kt index 4c4f008873..214fa860aa 100644 --- a/app/src/main/java/com/machiav3lli/backup/utils/SystemUtils.kt +++ b/app/src/main/java/com/machiav3lli/backup/utils/SystemUtils.kt @@ -93,7 +93,7 @@ object SystemUtils { throw Exception("${file.name} is empty or cannot be read") val sendIntent = Intent().apply { action = Intent.ACTION_SEND - type = "text/*" + type = "text/plain" flags = Intent.FLAG_GRANT_READ_URI_PERMISSION putExtra(Intent.EXTRA_SUBJECT, "[NeoBackup] ${file.name}") if (asFile) From b0cade3f3ed52fb83b391f1a8ec1218615196832 Mon Sep 17 00:00:00 2001 From: hg42 Date: Sun, 25 Feb 2024 04:18:17 +0100 Subject: [PATCH 7/7] fix renameDamagedToERROR for props without dir --- .../backup/handler/BackendController.kt | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/machiav3lli/backup/handler/BackendController.kt b/app/src/main/java/com/machiav3lli/backup/handler/BackendController.kt index 7b44afc0d5..bc0d0f6051 100644 --- a/app/src/main/java/com/machiav3lli/backup/handler/BackendController.kt +++ b/app/src/main/java/com/machiav3lli/backup/handler/BackendController.kt @@ -218,10 +218,23 @@ suspend fun scanBackups( renamer: (() -> Unit)? = null, ) { hitBusy() + try { - beginNanoTimer("scanBackups.${if (packageName.isEmpty()) "" else "package."}onPropsFile") - onPropsFile(file) - endNanoTimer("scanBackups.${if (packageName.isEmpty()) "" else "package."}onPropsFile") + if (file.name == BACKUP_INSTANCE_PROPERTIES_INDIR + || + (file.name?.removeSuffix( + ".$PROP_NAME" + )?.let { + file.parent?.findFile( + it + ) + } != null) + ) { + beginNanoTimer("scanBackups.${if (packageName.isEmpty()) "" else "package."}onPropsFile") + onPropsFile(file) + endNanoTimer("scanBackups.${if (packageName.isEmpty()) "" else "package."}onPropsFile") + } else + renameDamagedToERROR(file, "no-dir") } catch (_: Throwable) { if (renamer != null) renamer() @@ -278,7 +291,6 @@ suspend fun scanBackups( suspend fun processFile( file: StorageFile, ) { - checkThreadStats() val name = file.name ?: "" @@ -431,6 +443,7 @@ suspend fun scanBackups( } } } + if (packageName.isEmpty()) { traceBackupsScanPackage { "queue total ----> $total" } if (suspicious.get() > 0)