@@ -9,6 +9,7 @@ import android.app.backup.BackupProgress
9
9
import android.app.backup.BackupTransport.AGENT_ERROR
10
10
import android.app.backup.IBackupObserver
11
11
import android.content.Context
12
+ import android.content.Intent
12
13
import android.content.pm.ApplicationInfo.FLAG_SYSTEM
13
14
import android.content.pm.PackageManager.NameNotFoundException
14
15
import android.os.Looper
@@ -25,6 +26,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.NOT_ALLOWED
25
26
import com.stevesoltys.seedvault.repo.AppBackupManager
26
27
import com.stevesoltys.seedvault.repo.hexFromProto
27
28
import com.stevesoltys.seedvault.settings.SettingsManager
29
+ import com.stevesoltys.seedvault.transport.backup.FinalizeBackupService
28
30
import com.stevesoltys.seedvault.transport.backup.PackageService
29
31
import com.stevesoltys.seedvault.worker.AppBackupPruneWorker
30
32
import com.stevesoltys.seedvault.worker.BackupRequester
@@ -115,7 +117,7 @@ internal class NotificationBackupObserver(
115
117
// this should only ever happen for system apps, as we use only d2d now
116
118
if (target in launchableSystemApps) {
117
119
val packageInfo = context.packageManager.getPackageInfo(target, 0 )
118
- metadataManager.onPackageBackupError(packageInfo, NOT_ALLOWED )
120
+ metadataManager.onPackageBackupError(packageInfo, NOT_ALLOWED )
119
121
}
120
122
}
121
123
@@ -161,32 +163,23 @@ internal class NotificationBackupObserver(
161
163
// since the rest of packages from the failed chunk won't get backed up.
162
164
// So we either re-include those packages somehow (may fail again in a loop!)
163
165
// or we simply fail the entire backup which may cause more failures for users :(
164
- var success = status == 0
165
- val total = try {
166
- packageService.allUserPackages.size
167
- } catch (e: Exception ) {
168
- Log .e(TAG , " Error getting number of all user packages: " , e)
169
- requestedPackages
170
- }
171
- val snapshot = runBlocking {
172
- check(! Looper .getMainLooper().isCurrentThread)
173
- Log .d(TAG , " Finalizing backup..." )
174
- val snapshot = appBackupManager.afterBackupFinished(success)
175
- success = snapshot != null
176
- snapshot
177
- }
178
- val size = if (snapshot != null ) { // TODO for later: count size of APKs separately
179
- val chunkIds = snapshot.appsMap.values.flatMap { it.chunkIdsList }
180
- chunkIds.sumOf {
181
- snapshot.blobsMap[it.hexFromProto()]?.uncompressedLength?.toLong() ? : 0L
166
+ val success = status == 0
167
+ val i = Intent (context, FinalizeBackupService ::class .java)
168
+ try {
169
+ // Starting a foreground service, because the system may freeze/kill us otherwise
170
+ // before we are done here, because the TransportService gets destroyed now
171
+ // and the wakelock the system holds for us gets released. See #866 for more info.
172
+ context.startService(i)
173
+ // finalize backup only when success is true
174
+ val error = ! success || ! finalizeBackup()
175
+ if (error) {
176
+ runBlocking {
177
+ appBackupManager.afterBackupFinished(false )
178
+ }
179
+ nm.onBackupError()
182
180
}
183
- } else 0L
184
- if (success) {
185
- nm.onBackupSuccess(numPackagesToReport, total, size)
186
- // prune old backups
187
- AppBackupPruneWorker .scheduleNow(context)
188
- } else {
189
- nm.onBackupError()
181
+ } finally {
182
+ context.stopService(i)
190
183
}
191
184
}
192
185
}
@@ -209,6 +202,38 @@ internal class NotificationBackupObserver(
209
202
nm.onBackupUpdate(name, numPackages, requestedPackages)
210
203
}
211
204
205
+ /* *
206
+ * Returns true, if finalizing was successful.
207
+ */
208
+ private fun finalizeBackup (): Boolean {
209
+ // finalize and save snapshot
210
+ val snapshot = runBlocking {
211
+ check(! Looper .getMainLooper().isCurrentThread) // off UiThread
212
+ Log .d(TAG , " Finalizing backup..." )
213
+ appBackupManager.afterBackupFinished(true )
214
+ }
215
+ // abort on error
216
+ if (snapshot == null ) return false
217
+
218
+ // get info about backup
219
+ val total = try {
220
+ packageService.allUserPackages.size
221
+ } catch (e: Exception ) {
222
+ Log .e(TAG , " Error getting number of all user packages: " , e)
223
+ requestedPackages
224
+ }
225
+ val size = snapshot.appsMap.values.flatMap {
226
+ it.chunkIdsList // TODO for later: count size of APKs separately
227
+ }.sumOf {
228
+ snapshot.blobsMap[it.hexFromProto()]?.uncompressedLength?.toLong() ? : 0L
229
+ }
230
+ // show notification
231
+ nm.onBackupSuccess(numPackagesToReport, total, size)
232
+ // prune old backups
233
+ AppBackupPruneWorker .scheduleNow(context)
234
+ return true
235
+ }
236
+
212
237
private fun getAppName (packageId : String ): CharSequence = getAppName(context, packageId)
213
238
214
239
}
0 commit comments