Loading packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreFileArchiver.kt +1 −1 Original line number Original line Diff line number Diff line Loading @@ -62,7 +62,7 @@ internal class BackupRestoreFileArchiver( } } Log.i(LOG_TAG, "[$name] Restore ${data.size()} bytes for $key to $file") Log.i(LOG_TAG, "[$name] Restore ${data.size()} bytes for $key to $file") val inputStream = LimitedNoCloseInputStream(data) val inputStream = LimitedNoCloseInputStream(data) checksum.reset() val checksum = createChecksum() val checkedInputStream = CheckedInputStream(inputStream, checksum) val checkedInputStream = CheckedInputStream(inputStream, checksum) try { try { val codec = BackupCodec.fromId(checkedInputStream.read().toByte()) val codec = BackupCodec.fromId(checkedInputStream.read().toByte()) Loading packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt +27 −23 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ import java.io.OutputStream import java.util.zip.CRC32 import java.util.zip.CRC32 import java.util.zip.CheckedInputStream import java.util.zip.CheckedInputStream import java.util.zip.CheckedOutputStream import java.util.zip.CheckedOutputStream import java.util.zip.Checksum internal const val LOG_TAG = "BackupRestoreStorage" internal const val LOG_TAG = "BackupRestoreStorage" Loading @@ -54,15 +55,6 @@ abstract class BackupRestoreStorage : BackupHelper { */ */ abstract val name: String abstract val name: String private val entities: List<BackupRestoreEntity> by lazy { createBackupRestoreEntities() } /** * Checksum of the data. * * Always call [java.util.zip.Checksum.reset] before using it. */ protected val checksum = CRC32() /** /** * Entity states represented by checksum. * Entity states represented by checksum. * * Loading @@ -70,13 +62,16 @@ abstract class BackupRestoreStorage : BackupHelper { */ */ protected val entityStates = MutableScatterMap<String, Long>() protected val entityStates = MutableScatterMap<String, Long>() /** Entities created by [createBackupRestoreEntities]. This field is for restore only. */ private var entities: List<BackupRestoreEntity>? = null /** Entities to back up and restore. */ /** Entities to back up and restore. */ abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity> abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity> /** Default codec used to encode/decode the entity data. */ /** Default codec used to encode/decode the entity data. */ open fun defaultCodec(): BackupCodec = BackupZipCodec.BEST_COMPRESSION open fun defaultCodec(): BackupCodec = BackupZipCodec.BEST_COMPRESSION override fun performBackup( final override fun performBackup( oldState: ParcelFileDescriptor?, oldState: ParcelFileDescriptor?, data: BackupDataOutput, data: BackupDataOutput, newState: ParcelFileDescriptor, newState: ParcelFileDescriptor, Loading @@ -88,6 +83,9 @@ abstract class BackupRestoreStorage : BackupHelper { return return } } Log.i(LOG_TAG, "[$name] Backup start") Log.i(LOG_TAG, "[$name] Backup start") val checksum = createChecksum() // recreate entities for backup to avoid stale states val entities = createBackupRestoreEntities() for (entity in entities) { for (entity in entities) { val key = entity.key val key = entity.key val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream() Loading @@ -103,7 +101,8 @@ abstract class BackupRestoreStorage : BackupHelper { } } when (result) { when (result) { EntityBackupResult.UPDATE -> { EntityBackupResult.UPDATE -> { if (updateEntityState(key)) { val value = checksum.value if (entityStates.put(key, value) != value) { val payload = outputStream.toByteArray() val payload = outputStream.toByteArray() val size = payload.size val size = payload.size data.writeEntityHeader(key, size) data.writeEntityHeader(key, size) Loading @@ -126,15 +125,10 @@ abstract class BackupRestoreStorage : BackupHelper { } } } } } } newState.writeEntityStates(entityStates) newState.writeAndClearEntityStates() Log.i(LOG_TAG, "[$name] Backup end") Log.i(LOG_TAG, "[$name] Backup end") } } private fun updateEntityState(key: String): Boolean { val value = checksum.value return entityStates.put(key, value) != value } /** Returns if backup is enabled. */ /** Returns if backup is enabled. */ open fun enableBackup(backupContext: BackupContext): Boolean = true open fun enableBackup(backupContext: BackupContext): Boolean = true Loading @@ -144,13 +138,14 @@ abstract class BackupRestoreStorage : BackupHelper { return codec.encode(outputStream) return codec.encode(outputStream) } } /** This callback is invoked for every backed up entity. */ override fun restoreEntity(data: BackupDataInputStream) { override fun restoreEntity(data: BackupDataInputStream) { val key = data.key val key = data.key if (!enableRestore()) { if (!enableRestore()) { Log.i(LOG_TAG, "[$name] Restore disabled, ignore entity $key") Log.i(LOG_TAG, "[$name] Restore disabled, ignore entity $key") return return } } val entity = entities.firstOrNull { it.key == key } val entity = ensureEntities().firstOrNull { it.key == key } if (entity == null) { if (entity == null) { Log.w(LOG_TAG, "[$name] Cannot find handler for entity $key") Log.w(LOG_TAG, "[$name] Cannot find handler for entity $key") return return Loading @@ -159,7 +154,7 @@ abstract class BackupRestoreStorage : BackupHelper { val restoreContext = RestoreContext(key) val restoreContext = RestoreContext(key) val codec = entity.codec() ?: defaultCodec() val codec = entity.codec() ?: defaultCodec() val inputStream = LimitedNoCloseInputStream(data) val inputStream = LimitedNoCloseInputStream(data) checksum.reset() val checksum = createChecksum() val checkedInputStream = CheckedInputStream(inputStream, checksum) val checkedInputStream = CheckedInputStream(inputStream, checksum) try { try { entity.restore(restoreContext, wrapRestoreInputStream(codec, checkedInputStream)) entity.restore(restoreContext, wrapRestoreInputStream(codec, checkedInputStream)) Loading @@ -169,6 +164,9 @@ abstract class BackupRestoreStorage : BackupHelper { } } } } private fun ensureEntities(): List<BackupRestoreEntity> = entities ?: createBackupRestoreEntities().also { entities = it } /** Returns if restore is enabled. */ /** Returns if restore is enabled. */ open fun enableRestore(): Boolean = true open fun enableRestore(): Boolean = true Loading @@ -185,7 +183,8 @@ abstract class BackupRestoreStorage : BackupHelper { } } final override fun writeNewStateDescription(newState: ParcelFileDescriptor) { final override fun writeNewStateDescription(newState: ParcelFileDescriptor) { newState.writeEntityStates(entityStates) entities = null // clear to reduce memory footprint newState.writeAndClearEntityStates() onRestoreFinished() onRestoreFinished() } } Loading Loading @@ -223,24 +222,29 @@ abstract class BackupRestoreStorage : BackupHelper { } } } } private fun ParcelFileDescriptor.writeEntityStates(state: MutableScatterMap<String, Long>) { private fun ParcelFileDescriptor.writeAndClearEntityStates() { // do not close the streams // do not close the streams val fileOutputStream = FileOutputStream(fileDescriptor) val fileOutputStream = FileOutputStream(fileDescriptor) val dataOutputStream = DataOutputStream(fileOutputStream) val dataOutputStream = DataOutputStream(fileOutputStream) try { try { dataOutputStream.writeByte(STATE_VERSION.toInt()) dataOutputStream.writeByte(STATE_VERSION.toInt()) dataOutputStream.writeInt(state.size) dataOutputStream.writeInt(entityStates.size) state.forEach { key, value -> entityStates.forEach { key, value -> dataOutputStream.writeUTF(key) dataOutputStream.writeUTF(key) dataOutputStream.writeLong(value) dataOutputStream.writeLong(value) } } } catch (exception: Exception) { } catch (exception: Exception) { Log.e(LOG_TAG, "[$name] Fail to write state file", exception) Log.e(LOG_TAG, "[$name] Fail to write state file", exception) } } entityStates.clear() entityStates.trim() // trim to reduce memory footprint } } companion object { companion object { private const val STATE_VERSION: Byte = 0 private const val STATE_VERSION: Byte = 0 /** Checksum for entity backup data. */ fun createChecksum(): Checksum = CRC32() } } } } Loading Loading
packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreFileArchiver.kt +1 −1 Original line number Original line Diff line number Diff line Loading @@ -62,7 +62,7 @@ internal class BackupRestoreFileArchiver( } } Log.i(LOG_TAG, "[$name] Restore ${data.size()} bytes for $key to $file") Log.i(LOG_TAG, "[$name] Restore ${data.size()} bytes for $key to $file") val inputStream = LimitedNoCloseInputStream(data) val inputStream = LimitedNoCloseInputStream(data) checksum.reset() val checksum = createChecksum() val checkedInputStream = CheckedInputStream(inputStream, checksum) val checkedInputStream = CheckedInputStream(inputStream, checksum) try { try { val codec = BackupCodec.fromId(checkedInputStream.read().toByte()) val codec = BackupCodec.fromId(checkedInputStream.read().toByte()) Loading
packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt +27 −23 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ import java.io.OutputStream import java.util.zip.CRC32 import java.util.zip.CRC32 import java.util.zip.CheckedInputStream import java.util.zip.CheckedInputStream import java.util.zip.CheckedOutputStream import java.util.zip.CheckedOutputStream import java.util.zip.Checksum internal const val LOG_TAG = "BackupRestoreStorage" internal const val LOG_TAG = "BackupRestoreStorage" Loading @@ -54,15 +55,6 @@ abstract class BackupRestoreStorage : BackupHelper { */ */ abstract val name: String abstract val name: String private val entities: List<BackupRestoreEntity> by lazy { createBackupRestoreEntities() } /** * Checksum of the data. * * Always call [java.util.zip.Checksum.reset] before using it. */ protected val checksum = CRC32() /** /** * Entity states represented by checksum. * Entity states represented by checksum. * * Loading @@ -70,13 +62,16 @@ abstract class BackupRestoreStorage : BackupHelper { */ */ protected val entityStates = MutableScatterMap<String, Long>() protected val entityStates = MutableScatterMap<String, Long>() /** Entities created by [createBackupRestoreEntities]. This field is for restore only. */ private var entities: List<BackupRestoreEntity>? = null /** Entities to back up and restore. */ /** Entities to back up and restore. */ abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity> abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity> /** Default codec used to encode/decode the entity data. */ /** Default codec used to encode/decode the entity data. */ open fun defaultCodec(): BackupCodec = BackupZipCodec.BEST_COMPRESSION open fun defaultCodec(): BackupCodec = BackupZipCodec.BEST_COMPRESSION override fun performBackup( final override fun performBackup( oldState: ParcelFileDescriptor?, oldState: ParcelFileDescriptor?, data: BackupDataOutput, data: BackupDataOutput, newState: ParcelFileDescriptor, newState: ParcelFileDescriptor, Loading @@ -88,6 +83,9 @@ abstract class BackupRestoreStorage : BackupHelper { return return } } Log.i(LOG_TAG, "[$name] Backup start") Log.i(LOG_TAG, "[$name] Backup start") val checksum = createChecksum() // recreate entities for backup to avoid stale states val entities = createBackupRestoreEntities() for (entity in entities) { for (entity in entities) { val key = entity.key val key = entity.key val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream() Loading @@ -103,7 +101,8 @@ abstract class BackupRestoreStorage : BackupHelper { } } when (result) { when (result) { EntityBackupResult.UPDATE -> { EntityBackupResult.UPDATE -> { if (updateEntityState(key)) { val value = checksum.value if (entityStates.put(key, value) != value) { val payload = outputStream.toByteArray() val payload = outputStream.toByteArray() val size = payload.size val size = payload.size data.writeEntityHeader(key, size) data.writeEntityHeader(key, size) Loading @@ -126,15 +125,10 @@ abstract class BackupRestoreStorage : BackupHelper { } } } } } } newState.writeEntityStates(entityStates) newState.writeAndClearEntityStates() Log.i(LOG_TAG, "[$name] Backup end") Log.i(LOG_TAG, "[$name] Backup end") } } private fun updateEntityState(key: String): Boolean { val value = checksum.value return entityStates.put(key, value) != value } /** Returns if backup is enabled. */ /** Returns if backup is enabled. */ open fun enableBackup(backupContext: BackupContext): Boolean = true open fun enableBackup(backupContext: BackupContext): Boolean = true Loading @@ -144,13 +138,14 @@ abstract class BackupRestoreStorage : BackupHelper { return codec.encode(outputStream) return codec.encode(outputStream) } } /** This callback is invoked for every backed up entity. */ override fun restoreEntity(data: BackupDataInputStream) { override fun restoreEntity(data: BackupDataInputStream) { val key = data.key val key = data.key if (!enableRestore()) { if (!enableRestore()) { Log.i(LOG_TAG, "[$name] Restore disabled, ignore entity $key") Log.i(LOG_TAG, "[$name] Restore disabled, ignore entity $key") return return } } val entity = entities.firstOrNull { it.key == key } val entity = ensureEntities().firstOrNull { it.key == key } if (entity == null) { if (entity == null) { Log.w(LOG_TAG, "[$name] Cannot find handler for entity $key") Log.w(LOG_TAG, "[$name] Cannot find handler for entity $key") return return Loading @@ -159,7 +154,7 @@ abstract class BackupRestoreStorage : BackupHelper { val restoreContext = RestoreContext(key) val restoreContext = RestoreContext(key) val codec = entity.codec() ?: defaultCodec() val codec = entity.codec() ?: defaultCodec() val inputStream = LimitedNoCloseInputStream(data) val inputStream = LimitedNoCloseInputStream(data) checksum.reset() val checksum = createChecksum() val checkedInputStream = CheckedInputStream(inputStream, checksum) val checkedInputStream = CheckedInputStream(inputStream, checksum) try { try { entity.restore(restoreContext, wrapRestoreInputStream(codec, checkedInputStream)) entity.restore(restoreContext, wrapRestoreInputStream(codec, checkedInputStream)) Loading @@ -169,6 +164,9 @@ abstract class BackupRestoreStorage : BackupHelper { } } } } private fun ensureEntities(): List<BackupRestoreEntity> = entities ?: createBackupRestoreEntities().also { entities = it } /** Returns if restore is enabled. */ /** Returns if restore is enabled. */ open fun enableRestore(): Boolean = true open fun enableRestore(): Boolean = true Loading @@ -185,7 +183,8 @@ abstract class BackupRestoreStorage : BackupHelper { } } final override fun writeNewStateDescription(newState: ParcelFileDescriptor) { final override fun writeNewStateDescription(newState: ParcelFileDescriptor) { newState.writeEntityStates(entityStates) entities = null // clear to reduce memory footprint newState.writeAndClearEntityStates() onRestoreFinished() onRestoreFinished() } } Loading Loading @@ -223,24 +222,29 @@ abstract class BackupRestoreStorage : BackupHelper { } } } } private fun ParcelFileDescriptor.writeEntityStates(state: MutableScatterMap<String, Long>) { private fun ParcelFileDescriptor.writeAndClearEntityStates() { // do not close the streams // do not close the streams val fileOutputStream = FileOutputStream(fileDescriptor) val fileOutputStream = FileOutputStream(fileDescriptor) val dataOutputStream = DataOutputStream(fileOutputStream) val dataOutputStream = DataOutputStream(fileOutputStream) try { try { dataOutputStream.writeByte(STATE_VERSION.toInt()) dataOutputStream.writeByte(STATE_VERSION.toInt()) dataOutputStream.writeInt(state.size) dataOutputStream.writeInt(entityStates.size) state.forEach { key, value -> entityStates.forEach { key, value -> dataOutputStream.writeUTF(key) dataOutputStream.writeUTF(key) dataOutputStream.writeLong(value) dataOutputStream.writeLong(value) } } } catch (exception: Exception) { } catch (exception: Exception) { Log.e(LOG_TAG, "[$name] Fail to write state file", exception) Log.e(LOG_TAG, "[$name] Fail to write state file", exception) } } entityStates.clear() entityStates.trim() // trim to reduce memory footprint } } companion object { companion object { private const val STATE_VERSION: Byte = 0 private const val STATE_VERSION: Byte = 0 /** Checksum for entity backup data. */ fun createChecksum(): Checksum = CRC32() } } } } Loading