• 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.systemui.controls.controller.AuxiliaryPersistenceWrapper
31 import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
32 import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
33 import com.android.systemui.people.widget.PeopleBackupHelper
34 import com.android.systemui.settings.UserFileManagerImpl
35 
36 /**
37  * Helper for backing up elements in SystemUI
38  *
39  * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI. The
40  * helper can be used to back up any element that is stored in [Context.getFilesDir] or
41  * [Context.getSharedPreferences].
42  *
43  * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
44  * indicating that restoring is finished for a given user.
45  */
46 open class BackupHelper : BackupAgentHelper() {
47 
48     companion object {
49         const val TAG = "BackupHelper"
50         internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
51         private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
52         private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
53         private const val KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY =
54             "systemui.keyguard.quickaffordance.shared_preferences"
55         val controlsDataLock = Any()
56         const val ACTION_RESTORE_FINISHED = "com.android.systemui.backup.RESTORE_FINISHED"
57         const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
58     }
59 
onCreatenull60     override fun onCreate(userHandle: UserHandle, operationType: Int) {
61         super.onCreate()
62 
63         addControlsHelper(userHandle.identifier)
64 
65         val keys = PeopleBackupHelper.getFilesToBackup()
66         addHelper(
67             PEOPLE_TILES_BACKUP_KEY,
68             PeopleBackupHelper(this, userHandle, keys.toTypedArray())
69         )
70         addHelper(
71             KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY,
72             KeyguardQuickAffordanceBackupHelper(
73                 context = this,
74                 userId = userHandle.identifier,
75             ),
76         )
77     }
78 
onRestoreFinishednull79     override fun onRestoreFinished() {
80         super.onRestoreFinished()
81         val intent =
82             Intent(ACTION_RESTORE_FINISHED).apply {
83                 `package` = packageName
84                 putExtra(Intent.EXTRA_USER_ID, userId)
85                 flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
86             }
87         sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF)
88     }
89 
addControlsHelpernull90     private fun addControlsHelper(userId: Int) {
91         val file = UserFileManagerImpl.createFile(
92             userId = userId,
93             fileName = CONTROLS,
94         )
95         // The map in mapOf is guaranteed to be order preserving
96         val controlsMap = mapOf(file.getPath() to getPPControlsFile(this, userId))
97         NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
98             addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
99         }
100     }
101 
102     /**
103      * Helper class for restoring files ONLY if they are not present.
104      *
105      * A [Map] between filenames and actions (functions) is passed to indicate post processing
106      * actions to be taken after each file is restored.
107      *
108      * @property lock a lock to hold while backing up and restoring the files.
109      * @property context the context of the [BackupAgent]
110      * @property fileNamesAndPostProcess a map from the filenames to back up and the post processing
111      * ```
112      *                                   actions to take
113      * ```
114      */
115     private class NoOverwriteFileBackupHelper(
116         val lock: Any,
117         val context: Context,
118         val fileNamesAndPostProcess: Map<String, () -> Unit>
119     ) : FileBackupHelper(context, *fileNamesAndPostProcess.keys.toTypedArray()) {
120 
restoreEntitynull121         override fun restoreEntity(data: BackupDataInputStream) {
122             val file = Environment.buildPath(context.filesDir, data.key)
123             if (file.exists()) {
124                 Log.w(TAG, "File " + data.key + " already exists. Skipping restore.")
125                 return
126             }
127             synchronized(lock) {
128                 super.restoreEntity(data)
129                 fileNamesAndPostProcess.get(data.key)?.invoke()
130             }
131         }
132 
performBackupnull133         override fun performBackup(
134             oldState: ParcelFileDescriptor?,
135             data: BackupDataOutput?,
136             newState: ParcelFileDescriptor?
137         ) {
138             synchronized(lock) { super.performBackup(oldState, data, newState) }
139         }
140     }
141 }
142 
getPPControlsFilenull143 private fun getPPControlsFile(context: Context, userId: Int): () -> Unit {
144     return {
145         val file = UserFileManagerImpl.createFile(
146             userId = userId,
147             fileName = BackupHelper.CONTROLS,
148         )
149         if (file.exists()) {
150             val dest = UserFileManagerImpl.createFile(
151                 userId = userId,
152                 fileName = AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME,
153             )
154             file.copyTo(dest)
155             val jobScheduler = context.getSystemService(JobScheduler::class.java)
156             jobScheduler?.schedule(
157                 AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
158             )
159         }
160     }
161 }
162