• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Flags
32 import com.android.systemui.backup.BackupHelper.Companion.ACTION_RESTORE_FINISHED
33 import com.android.systemui.communal.data.backup.CommunalBackupHelper
34 import com.android.systemui.communal.data.backup.CommunalBackupUtils
35 import com.android.systemui.communal.domain.backup.CommunalPrefsBackupHelper
36 import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper
37 import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
38 import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
39 import com.android.systemui.people.widget.PeopleBackupHelper
40 import com.android.systemui.qs.panels.domain.backup.QSPreferencesBackupHelper
41 import com.android.systemui.res.R
42 import com.android.systemui.settings.UserFileManagerImpl
43 
44 /**
45  * Helper for backing up elements in SystemUI
46  *
47  * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI. The
48  * helper can be used to back up any element that is stored in [Context.getFilesDir] or
49  * [Context.getSharedPreferences].
50  *
51  * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
52  * indicating that restoring is finished for a given user.
53  */
54 open class BackupHelper : BackupAgentHelper() {
55 
56     companion object {
57         const val TAG = "BackupHelper"
58         internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
59         private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
60         private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
61         private const val KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY =
62             "systemui.keyguard.quickaffordance.shared_preferences"
63         private const val COMMUNAL_PREFS_BACKUP_KEY = "systemui.communal.shared_preferences"
64         private const val COMMUNAL_STATE_BACKUP_KEY = "systemui.communal_state"
65         private const val QS_PREFERENCES_BACKUP_KEY = "systemui.qs.shared_preferences"
66         val controlsDataLock = Any()
67         const val ACTION_RESTORE_FINISHED = "com.android.systemui.backup.RESTORE_FINISHED"
68         const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
69     }
70 
onCreatenull71     override fun onCreate(userHandle: UserHandle) {
72         super.onCreate(userHandle)
73 
74         addControlsHelper(userHandle.identifier)
75 
76         val keys = PeopleBackupHelper.getFilesToBackup()
77         addHelper(
78             PEOPLE_TILES_BACKUP_KEY,
79             PeopleBackupHelper(this, userHandle, keys.toTypedArray()),
80         )
81         addHelper(
82             KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY,
83             KeyguardQuickAffordanceBackupHelper(context = this, userId = userHandle.identifier),
84         )
85         addHelper(
86             QS_PREFERENCES_BACKUP_KEY,
87             QSPreferencesBackupHelper(context = this, userId = userHandle.identifier),
88         )
89         if (communalEnabled()) {
90             addHelper(
91                 COMMUNAL_PREFS_BACKUP_KEY,
92                 CommunalPrefsBackupHelper(context = this, userId = userHandle.identifier),
93             )
94             addHelper(
95                 COMMUNAL_STATE_BACKUP_KEY,
96                 CommunalBackupHelper(userHandle, CommunalBackupUtils(context = this)),
97             )
98         }
99     }
100 
onRestoreFinishednull101     override fun onRestoreFinished() {
102         super.onRestoreFinished()
103         val intent =
104             Intent(ACTION_RESTORE_FINISHED).apply {
105                 `package` = packageName
106                 putExtra(Intent.EXTRA_USER_ID, userId)
107                 flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
108             }
109         sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF)
110     }
111 
addControlsHelpernull112     private fun addControlsHelper(userId: Int) {
113         val file = UserFileManagerImpl.createFile(userId = userId, fileName = CONTROLS)
114         // The map in mapOf is guaranteed to be order preserving
115         val controlsMap = mapOf(file.getPath() to getPPControlsFile(this, userId))
116         NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
117             addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
118         }
119     }
120 
communalEnablednull121     private fun communalEnabled(): Boolean {
122         return resources.getBoolean(R.bool.config_communalServiceEnabled) ||
123             (Flags.glanceableHubV2() &&
124                 resources.getBoolean(com.android.internal.R.bool.config_glanceableHubEnabled))
125     }
126 
127     /**
128      * Helper class for restoring files ONLY if they are not present.
129      *
130      * A [Map] between filenames and actions (functions) is passed to indicate post processing
131      * actions to be taken after each file is restored.
132      *
133      * @property lock a lock to hold while backing up and restoring the files.
134      * @property context the context of the [BackupAgent]
135      * @property fileNamesAndPostProcess a map from the filenames to back up and the post processing
136      *
137      * ```
138      *                                   actions to take
139      * ```
140      */
141     private class NoOverwriteFileBackupHelper(
142         val lock: Any,
143         val context: Context,
144         val fileNamesAndPostProcess: Map<String, () -> Unit>,
145     ) : FileBackupHelper(context, *fileNamesAndPostProcess.keys.toTypedArray()) {
146 
restoreEntitynull147         override fun restoreEntity(data: BackupDataInputStream) {
148             Log.d(TAG, "Starting restore for ${data.key} for user ${context.userId}")
149             val file = Environment.buildPath(context.filesDir, data.key)
150             if (file.exists()) {
151                 Log.w(TAG, "File " + data.key + " already exists. Skipping restore.")
152                 return
153             }
154             synchronized(lock) {
155                 traceSection("File restore: ${data.key}") { super.restoreEntity(data) }
156                 Log.d(
157                     TAG,
158                     "Finishing restore for ${data.key} for user ${context.userId}. " +
159                         "Starting postProcess.",
160                 )
161                 traceSection("Postprocess: ${data.key}") {
162                     fileNamesAndPostProcess.get(data.key)?.invoke()
163                 }
164                 Log.d(TAG, "Finishing postprocess for ${data.key} for user ${context.userId}.")
165             }
166         }
167 
performBackupnull168         override fun performBackup(
169             oldState: ParcelFileDescriptor?,
170             data: BackupDataOutput?,
171             newState: ParcelFileDescriptor?,
172         ) {
173             synchronized(lock) { super.performBackup(oldState, data, newState) }
174         }
175     }
176 }
177 
getPPControlsFilenull178 private fun getPPControlsFile(context: Context, userId: Int): () -> Unit {
179     return {
180         val file = UserFileManagerImpl.createFile(userId = userId, fileName = BackupHelper.CONTROLS)
181         if (file.exists()) {
182             val dest =
183                 UserFileManagerImpl.createFile(
184                     userId = userId,
185                     fileName = AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME,
186                 )
187             file.copyTo(dest)
188             val jobScheduler = context.getSystemService(JobScheduler::class.java)
189             jobScheduler?.schedule(
190                 AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
191             )
192         }
193     }
194 }
195