Loading packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt +63 −50 Original line number Original line Diff line number Diff line Loading @@ -26,23 +26,10 @@ import java.util.concurrent.ConcurrentHashMap /** Manager of [BackupRestoreStorage]. */ /** Manager of [BackupRestoreStorage]. */ class BackupRestoreStorageManager private constructor(private val application: Application) { class BackupRestoreStorageManager private constructor(private val application: Application) { private val storages = ConcurrentHashMap<String, BackupRestoreStorage>() private val storageWrappers = ConcurrentHashMap<String, StorageWrapper>() private val executor = MoreExecutors.directExecutor() private val executor = MoreExecutors.directExecutor() private val observer = Observer { reason -> notifyBackupManager(null, reason) } private val keyedObserver = KeyedObserver<Any?> { key, reason -> notifyBackupManager(key, reason) } private fun notifyBackupManager(key: Any?, reason: Int) { // prefer not triggering backup immediately after restore if (reason == ChangeReason.RESTORE) return // TODO: log storage name Log.d(LOG_TAG, "Notify BackupManager data changed for change: key=$key") BackupManager.dataChanged(application.packageName) } /** /** * Adds all the registered [BackupRestoreStorage] as the helpers of given [BackupAgentHelper]. * Adds all the registered [BackupRestoreStorage] as the helpers of given [BackupAgentHelper]. * * Loading @@ -52,7 +39,8 @@ class BackupRestoreStorageManager private constructor(private val application: A */ */ fun addBackupAgentHelpers(backupAgentHelper: BackupAgentHelper) { fun addBackupAgentHelpers(backupAgentHelper: BackupAgentHelper) { val fileStorages = mutableListOf<BackupRestoreFileStorage>() val fileStorages = mutableListOf<BackupRestoreFileStorage>() for ((keyPrefix, storage) in storages) { for ((keyPrefix, storageWrapper) in storageWrappers) { val storage = storageWrapper.storage if (storage is BackupRestoreFileStorage) { if (storage is BackupRestoreFileStorage) { fileStorages.add(storage) fileStorages.add(storage) } else { } else { Loading @@ -70,15 +58,8 @@ class BackupRestoreStorageManager private constructor(private val application: A * The observers of the storages will be notified. * The observers of the storages will be notified. */ */ fun onRestoreFinished() { fun onRestoreFinished() { for (storage in storages.values) { for (storageWrapper in storageWrappers.values) { storage.notifyRestoreFinished() storageWrapper.notifyRestoreFinished() } } private fun BackupRestoreStorage.notifyRestoreFinished() { when (this) { is KeyedObservable<*> -> notifyChange(ChangeReason.RESTORE) is Observable -> notifyChange(ChangeReason.RESTORE) } } } } Loading @@ -99,19 +80,38 @@ class BackupRestoreStorageManager private constructor(private val application: A fun add(storage: BackupRestoreStorage) { fun add(storage: BackupRestoreStorage) { if (storage is BackupRestoreFileStorage) storage.checkFilePaths() if (storage is BackupRestoreFileStorage) storage.checkFilePaths() val name = storage.name val name = storage.name val oldStorage = storages.put(name, storage) val oldStorage = storageWrappers.put(name, StorageWrapper(storage))?.storage if (oldStorage != null) { if (oldStorage != null) { throw IllegalStateException( throw IllegalStateException( "Storage name '$name' conflicts:\n\told: $oldStorage\n\tnew: $storage" "Storage name '$name' conflicts:\n\told: $oldStorage\n\tnew: $storage" ) ) } } storage.addObserver() } } private fun BackupRestoreStorage.addObserver() { /** Removes all the storages. */ when (this) { fun removeAll() { is KeyedObservable<*> -> addObserver(keyedObserver, executor) for ((name, _) in storageWrappers) remove(name) is Observable -> addObserver(observer, executor) } /** Removes storage with given name. */ fun remove(name: String): BackupRestoreStorage? { val storageWrapper = storageWrappers.remove(name) storageWrapper?.removeObserver() return storageWrapper?.storage } /** Returns storage with given name. */ fun get(name: String): BackupRestoreStorage? = storageWrappers[name]?.storage /** Returns storage with given name, exception is raised if not found. */ fun getOrThrow(name: String): BackupRestoreStorage = storageWrappers[name]!!.storage private inner class StorageWrapper(val storage: BackupRestoreStorage) : Observer, KeyedObserver<Any?> { init { when (storage) { is KeyedObservable<*> -> storage.addObserver(this, executor) is Observable -> storage.addObserver(this, executor) else -> else -> throw IllegalArgumentException( throw IllegalArgumentException( "$this does not implement either KeyedObservable or Observable" "$this does not implement either KeyedObservable or Observable" Loading @@ -119,30 +119,43 @@ class BackupRestoreStorageManager private constructor(private val application: A } } } } /** Removes all the storages. */ override fun onChanged(reason: Int) = onKeyChanged(null, reason) fun removeAll() { for ((name, _) in storages) remove(name) } /** Removes storage with given name. */ override fun onKeyChanged(key: Any?, reason: Int) { fun remove(name: String): BackupRestoreStorage? { notifyBackupManager(key, reason) val storage = storages.remove(name) storage?.removeObserver() return storage } } private fun BackupRestoreStorage.removeObserver() { private fun notifyBackupManager(key: Any?, reason: Int) { when (this) { val name = storage.name is KeyedObservable<*> -> removeObserver(keyedObserver) // prefer not triggering backup immediately after restore is Observable -> removeObserver(observer) if (reason == ChangeReason.RESTORE) { Log.d( LOG_TAG, "Notify BackupManager dataChanged ignored for restore: storage=$name key=$key" ) return } } Log.d( LOG_TAG, "Notify BackupManager dataChanged: storage=$name key=$key reason=$reason" ) BackupManager.dataChanged(application.packageName) } } /** Returns storage with given name. */ fun removeObserver() { fun get(name: String): BackupRestoreStorage? = storages[name] when (storage) { is KeyedObservable<*> -> storage.removeObserver(this) is Observable -> storage.removeObserver(this) } } /** Returns storage with given name, exception is raised if not found. */ fun notifyRestoreFinished() { fun getOrThrow(name: String): BackupRestoreStorage = storages[name]!! when (storage) { is KeyedObservable<*> -> storage.notifyChange(ChangeReason.RESTORE) is Observable -> storage.notifyChange(ChangeReason.RESTORE) } } } companion object { companion object { @Volatile private var instance: BackupRestoreStorageManager? = null @Volatile private var instance: BackupRestoreStorageManager? = null Loading Loading
packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt +63 −50 Original line number Original line Diff line number Diff line Loading @@ -26,23 +26,10 @@ import java.util.concurrent.ConcurrentHashMap /** Manager of [BackupRestoreStorage]. */ /** Manager of [BackupRestoreStorage]. */ class BackupRestoreStorageManager private constructor(private val application: Application) { class BackupRestoreStorageManager private constructor(private val application: Application) { private val storages = ConcurrentHashMap<String, BackupRestoreStorage>() private val storageWrappers = ConcurrentHashMap<String, StorageWrapper>() private val executor = MoreExecutors.directExecutor() private val executor = MoreExecutors.directExecutor() private val observer = Observer { reason -> notifyBackupManager(null, reason) } private val keyedObserver = KeyedObserver<Any?> { key, reason -> notifyBackupManager(key, reason) } private fun notifyBackupManager(key: Any?, reason: Int) { // prefer not triggering backup immediately after restore if (reason == ChangeReason.RESTORE) return // TODO: log storage name Log.d(LOG_TAG, "Notify BackupManager data changed for change: key=$key") BackupManager.dataChanged(application.packageName) } /** /** * Adds all the registered [BackupRestoreStorage] as the helpers of given [BackupAgentHelper]. * Adds all the registered [BackupRestoreStorage] as the helpers of given [BackupAgentHelper]. * * Loading @@ -52,7 +39,8 @@ class BackupRestoreStorageManager private constructor(private val application: A */ */ fun addBackupAgentHelpers(backupAgentHelper: BackupAgentHelper) { fun addBackupAgentHelpers(backupAgentHelper: BackupAgentHelper) { val fileStorages = mutableListOf<BackupRestoreFileStorage>() val fileStorages = mutableListOf<BackupRestoreFileStorage>() for ((keyPrefix, storage) in storages) { for ((keyPrefix, storageWrapper) in storageWrappers) { val storage = storageWrapper.storage if (storage is BackupRestoreFileStorage) { if (storage is BackupRestoreFileStorage) { fileStorages.add(storage) fileStorages.add(storage) } else { } else { Loading @@ -70,15 +58,8 @@ class BackupRestoreStorageManager private constructor(private val application: A * The observers of the storages will be notified. * The observers of the storages will be notified. */ */ fun onRestoreFinished() { fun onRestoreFinished() { for (storage in storages.values) { for (storageWrapper in storageWrappers.values) { storage.notifyRestoreFinished() storageWrapper.notifyRestoreFinished() } } private fun BackupRestoreStorage.notifyRestoreFinished() { when (this) { is KeyedObservable<*> -> notifyChange(ChangeReason.RESTORE) is Observable -> notifyChange(ChangeReason.RESTORE) } } } } Loading @@ -99,19 +80,38 @@ class BackupRestoreStorageManager private constructor(private val application: A fun add(storage: BackupRestoreStorage) { fun add(storage: BackupRestoreStorage) { if (storage is BackupRestoreFileStorage) storage.checkFilePaths() if (storage is BackupRestoreFileStorage) storage.checkFilePaths() val name = storage.name val name = storage.name val oldStorage = storages.put(name, storage) val oldStorage = storageWrappers.put(name, StorageWrapper(storage))?.storage if (oldStorage != null) { if (oldStorage != null) { throw IllegalStateException( throw IllegalStateException( "Storage name '$name' conflicts:\n\told: $oldStorage\n\tnew: $storage" "Storage name '$name' conflicts:\n\told: $oldStorage\n\tnew: $storage" ) ) } } storage.addObserver() } } private fun BackupRestoreStorage.addObserver() { /** Removes all the storages. */ when (this) { fun removeAll() { is KeyedObservable<*> -> addObserver(keyedObserver, executor) for ((name, _) in storageWrappers) remove(name) is Observable -> addObserver(observer, executor) } /** Removes storage with given name. */ fun remove(name: String): BackupRestoreStorage? { val storageWrapper = storageWrappers.remove(name) storageWrapper?.removeObserver() return storageWrapper?.storage } /** Returns storage with given name. */ fun get(name: String): BackupRestoreStorage? = storageWrappers[name]?.storage /** Returns storage with given name, exception is raised if not found. */ fun getOrThrow(name: String): BackupRestoreStorage = storageWrappers[name]!!.storage private inner class StorageWrapper(val storage: BackupRestoreStorage) : Observer, KeyedObserver<Any?> { init { when (storage) { is KeyedObservable<*> -> storage.addObserver(this, executor) is Observable -> storage.addObserver(this, executor) else -> else -> throw IllegalArgumentException( throw IllegalArgumentException( "$this does not implement either KeyedObservable or Observable" "$this does not implement either KeyedObservable or Observable" Loading @@ -119,30 +119,43 @@ class BackupRestoreStorageManager private constructor(private val application: A } } } } /** Removes all the storages. */ override fun onChanged(reason: Int) = onKeyChanged(null, reason) fun removeAll() { for ((name, _) in storages) remove(name) } /** Removes storage with given name. */ override fun onKeyChanged(key: Any?, reason: Int) { fun remove(name: String): BackupRestoreStorage? { notifyBackupManager(key, reason) val storage = storages.remove(name) storage?.removeObserver() return storage } } private fun BackupRestoreStorage.removeObserver() { private fun notifyBackupManager(key: Any?, reason: Int) { when (this) { val name = storage.name is KeyedObservable<*> -> removeObserver(keyedObserver) // prefer not triggering backup immediately after restore is Observable -> removeObserver(observer) if (reason == ChangeReason.RESTORE) { Log.d( LOG_TAG, "Notify BackupManager dataChanged ignored for restore: storage=$name key=$key" ) return } } Log.d( LOG_TAG, "Notify BackupManager dataChanged: storage=$name key=$key reason=$reason" ) BackupManager.dataChanged(application.packageName) } } /** Returns storage with given name. */ fun removeObserver() { fun get(name: String): BackupRestoreStorage? = storages[name] when (storage) { is KeyedObservable<*> -> storage.removeObserver(this) is Observable -> storage.removeObserver(this) } } /** Returns storage with given name, exception is raised if not found. */ fun notifyRestoreFinished() { fun getOrThrow(name: String): BackupRestoreStorage = storages[name]!! when (storage) { is KeyedObservable<*> -> storage.notifyChange(ChangeReason.RESTORE) is Observable -> storage.notifyChange(ChangeReason.RESTORE) } } } companion object { companion object { @Volatile private var instance: BackupRestoreStorageManager? = null @Volatile private var instance: BackupRestoreStorageManager? = null Loading