xref: /aosp_15_r20/frameworks/base/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.backup
18 
19 import android.app.backup.BackupAgentHelper
20 import android.app.backup.BackupDataInputStream
21 import android.app.backup.BackupDataOutput
22 import android.app.backup.FileBackupHelper
23 import android.app.job.JobScheduler
24 import android.content.Context
25 import android.content.Intent
26 import android.os.Environment
27 import android.os.ParcelFileDescriptor
28 import android.os.UserHandle
29 import android.util.Log
30 import com.android.app.tracing.traceSection
31 import com.android.systemui.backup.BackupHelper.Companion.ACTION_RESTORE_FINISHED
32 import com.android.systemui.communal.data.backup.CommunalBackupHelper
33 import com.android.systemui.communal.data.backup.CommunalBackupUtils
34 import com.android.systemui.communal.domain.backup.CommunalPrefsBackupHelper
35 import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper
36 import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
37 import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
38 import com.android.systemui.people.widget.PeopleBackupHelper
39 import com.android.systemui.qs.panels.domain.backup.QSPreferencesBackupHelper
40 import com.android.systemui.res.R
41 import com.android.systemui.settings.UserFileManagerImpl
42 
43 /**
44  * Helper for backing up elements in SystemUI
45  *
46  * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI. The
47  * helper can be used to back up any element that is stored in [Context.getFilesDir] or
48  * [Context.getSharedPreferences].
49  *
50  * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
51  * indicating that restoring is finished for a given user.
52  */
53 open class BackupHelper : BackupAgentHelper() {
54 
55     companion object {
56         const val TAG = "BackupHelper"
57         internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
58         private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
59         private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
60         private const val KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY =
61             "systemui.keyguard.quickaffordance.shared_preferences"
62         private const val COMMUNAL_PREFS_BACKUP_KEY = "systemui.communal.shared_preferences"
63         private const val COMMUNAL_STATE_BACKUP_KEY = "systemui.communal_state"
64         private const val QS_PREFERENCES_BACKUP_KEY = "systemui.qs.shared_preferences"
65         val controlsDataLock = Any()
66         const val ACTION_RESTORE_FINISHED = "com.android.systemui.backup.RESTORE_FINISHED"
67         const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
68     }
69 
onCreatenull70     override fun onCreate(userHandle: UserHandle) {
71         super.onCreate(userHandle)
72 
73         addControlsHelper(userHandle.identifier)
74 
75         val keys = PeopleBackupHelper.getFilesToBackup()
76         addHelper(
77             PEOPLE_TILES_BACKUP_KEY,
78             PeopleBackupHelper(this, userHandle, keys.toTypedArray()),
79         )
80         addHelper(
81             KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY,
82             KeyguardQuickAffordanceBackupHelper(context = this, userId = userHandle.identifier),
83         )
84         addHelper(
85             QS_PREFERENCES_BACKUP_KEY,
86             QSPreferencesBackupHelper(context = this, userId = userHandle.identifier),
87         )
88         if (communalEnabled()) {
89             addHelper(
90                 COMMUNAL_PREFS_BACKUP_KEY,
91                 CommunalPrefsBackupHelper(context = this, userId = userHandle.identifier),
92             )
93             addHelper(
94                 COMMUNAL_STATE_BACKUP_KEY,
95                 CommunalBackupHelper(userHandle, CommunalBackupUtils(context = this)),
96             )
97         }
98     }
99 
onRestoreFinishednull100     override fun onRestoreFinished() {
101         super.onRestoreFinished()
102         val intent =
103             Intent(ACTION_RESTORE_FINISHED).apply {
104                 `package` = packageName
105                 putExtra(Intent.EXTRA_USER_ID, userId)
106                 flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
107             }
108         sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF)
109     }
110 
addControlsHelpernull111     private fun addControlsHelper(userId: Int) {
112         val file = UserFileManagerImpl.createFile(userId = userId, fileName = CONTROLS)
113         // The map in mapOf is guaranteed to be order preserving
114         val controlsMap = mapOf(file.getPath() to getPPControlsFile(this, userId))
115         NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
116             addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
117         }
118     }
119 
communalEnablednull120     private fun communalEnabled(): Boolean {
121         return resources.getBoolean(R.bool.config_communalServiceEnabled)
122     }
123 
124     /**
125      * Helper class for restoring files ONLY if they are not present.
126      *
127      * A [Map] between filenames and actions (functions) is passed to indicate post processing
128      * actions to be taken after each file is restored.
129      *
130      * @property lock a lock to hold while backing up and restoring the files.
131      * @property context the context of the [BackupAgent]
132      * @property fileNamesAndPostProcess a map from the filenames to back up and the post processing
133      *
134      * ```
135      *                                   actions to take
136      * ```
137      */
138     private class NoOverwriteFileBackupHelper(
139         val lock: Any,
140         val context: Context,
141         val fileNamesAndPostProcess: Map<String, () -> Unit>,
142     ) : FileBackupHelper(context, *fileNamesAndPostProcess.keys.toTypedArray()) {
143 
restoreEntitynull144         override fun restoreEntity(data: BackupDataInputStream) {
145             Log.d(TAG, "Starting restore for ${data.key} for user ${context.userId}")
146             val file = Environment.buildPath(context.filesDir, data.key)
147             if (file.exists()) {
148                 Log.w(TAG, "File " + data.key + " already exists. Skipping restore.")
149                 return
150             }
151             synchronized(lock) {
152                 traceSection("File restore: ${data.key}") { super.restoreEntity(data) }
153                 Log.d(
154                     TAG,
155                     "Finishing restore for ${data.key} for user ${context.userId}. " +
156                         "Starting postProcess.",
157                 )
158                 traceSection("Postprocess: ${data.key}") {
159                     fileNamesAndPostProcess.get(data.key)?.invoke()
160                 }
161                 Log.d(TAG, "Finishing postprocess for ${data.key} for user ${context.userId}.")
162             }
163         }
164 
performBackupnull165         override fun performBackup(
166             oldState: ParcelFileDescriptor?,
167             data: BackupDataOutput?,
168             newState: ParcelFileDescriptor?,
169         ) {
170             synchronized(lock) { super.performBackup(oldState, data, newState) }
171         }
172     }
173 }
174 
getPPControlsFilenull175 private fun getPPControlsFile(context: Context, userId: Int): () -> Unit {
176     return {
177         val file = UserFileManagerImpl.createFile(userId = userId, fileName = BackupHelper.CONTROLS)
178         if (file.exists()) {
179             val dest =
180                 UserFileManagerImpl.createFile(
181                     userId = userId,
182                     fileName = AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME,
183                 )
184             file.copyTo(dest)
185             val jobScheduler = context.getSystemService(JobScheduler::class.java)
186             jobScheduler?.schedule(
187                 AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
188             )
189         }
190     }
191 }
192