BackupHandler.java revision f251e3509838e3fbc62ccdba9d4cfd0527f67acd
1/* 2 * Copyright (C) 2017 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 17package com.android.server.backup.internal; 18 19import android.app.AlarmManager; 20import android.app.backup.RestoreSet; 21import android.content.Intent; 22import android.os.Handler; 23import android.os.Looper; 24import android.os.Message; 25import android.os.RemoteException; 26import android.os.UserHandle; 27import android.util.EventLog; 28import android.util.Pair; 29import android.util.Slog; 30import com.android.internal.backup.IBackupTransport; 31import com.android.server.EventLogTags; 32import com.android.server.backup.BackupRestoreTask; 33import com.android.server.backup.RefactoredBackupManagerService; 34import com.android.server.backup.fullbackup.PerformAdbBackupTask; 35import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; 36import com.android.server.backup.params.AdbBackupParams; 37import com.android.server.backup.params.AdbParams; 38import com.android.server.backup.params.AdbRestoreParams; 39import com.android.server.backup.params.BackupParams; 40import com.android.server.backup.params.ClearParams; 41import com.android.server.backup.params.ClearRetryParams; 42import com.android.server.backup.params.RestoreGetSetsParams; 43import com.android.server.backup.params.RestoreParams; 44import com.android.server.backup.restore.PerformAdbRestoreTask; 45import com.android.server.backup.restore.PerformUnifiedRestoreTask; 46import java.io.File; 47import java.util.ArrayList; 48import java.util.Collections; 49import java.util.HashSet; 50 51/** 52 * Asynchronous backup/restore handler thread. 53 */ 54public class BackupHandler extends Handler { 55 56 private RefactoredBackupManagerService backupManagerService; 57 58 public BackupHandler( 59 RefactoredBackupManagerService backupManagerService, Looper looper) { 60 super(looper); 61 this.backupManagerService = backupManagerService; 62 } 63 64 public void handleMessage(Message msg) { 65 66 switch (msg.what) { 67 case RefactoredBackupManagerService.MSG_RUN_BACKUP: { 68 backupManagerService.mLastBackupPass = System.currentTimeMillis(); 69 70 IBackupTransport transport = backupManagerService.mTransportManager.getCurrentTransportBinder(); 71 if (transport == null) { 72 Slog.v(RefactoredBackupManagerService.TAG, "Backup requested but no transport available"); 73 synchronized (backupManagerService.mQueueLock) { 74 backupManagerService.mBackupRunning = false; 75 } 76 backupManagerService.mWakelock.release(); 77 break; 78 } 79 80 // snapshot the pending-backup set and work on that 81 ArrayList<BackupRequest> queue = new ArrayList<>(); 82 File oldJournal = backupManagerService.mJournal; 83 synchronized (backupManagerService.mQueueLock) { 84 // Do we have any work to do? Construct the work queue 85 // then release the synchronization lock to actually run 86 // the backup. 87 if (backupManagerService.mPendingBackups.size() > 0) { 88 for (BackupRequest b : backupManagerService.mPendingBackups.values()) { 89 queue.add(b); 90 } 91 if (RefactoredBackupManagerService.DEBUG) { 92 Slog.v(RefactoredBackupManagerService.TAG, "clearing pending backups"); 93 } 94 backupManagerService.mPendingBackups.clear(); 95 96 // Start a new backup-queue journal file too 97 backupManagerService.mJournal = null; 98 99 } 100 } 101 102 // At this point, we have started a new journal file, and the old 103 // file identity is being passed to the backup processing task. 104 // When it completes successfully, that old journal file will be 105 // deleted. If we crash prior to that, the old journal is parsed 106 // at next boot and the journaled requests fulfilled. 107 boolean staged = true; 108 if (queue.size() > 0) { 109 // Spin up a backup state sequence and set it running 110 try { 111 String dirName = transport.transportDirName(); 112 PerformBackupTask pbt = new PerformBackupTask( 113 backupManagerService, transport, dirName, queue, 114 oldJournal, null, null, Collections.<String>emptyList(), false, 115 false /* nonIncremental */); 116 Message pbtMessage = obtainMessage( 117 RefactoredBackupManagerService.MSG_BACKUP_RESTORE_STEP, pbt); 118 sendMessage(pbtMessage); 119 } catch (Exception e) { 120 // unable to ask the transport its dir name -- transient failure, since 121 // the above check succeeded. Try again next time. 122 Slog.e(RefactoredBackupManagerService.TAG, "Transport became unavailable attempting backup" 123 + " or error initializing backup task", e); 124 staged = false; 125 } 126 } else { 127 Slog.v(RefactoredBackupManagerService.TAG, "Backup requested but nothing pending"); 128 staged = false; 129 } 130 131 if (!staged) { 132 // if we didn't actually hand off the wakelock, rewind until next time 133 synchronized (backupManagerService.mQueueLock) { 134 backupManagerService.mBackupRunning = false; 135 } 136 backupManagerService.mWakelock.release(); 137 } 138 break; 139 } 140 141 case RefactoredBackupManagerService.MSG_BACKUP_RESTORE_STEP: { 142 try { 143 BackupRestoreTask task = (BackupRestoreTask) msg.obj; 144 if (RefactoredBackupManagerService.MORE_DEBUG) { 145 Slog.v(RefactoredBackupManagerService.TAG, "Got next step for " + task + ", executing"); 146 } 147 task.execute(); 148 } catch (ClassCastException e) { 149 Slog.e(RefactoredBackupManagerService.TAG, "Invalid backup task in flight, obj=" + msg.obj); 150 } 151 break; 152 } 153 154 case RefactoredBackupManagerService.MSG_OP_COMPLETE: { 155 try { 156 Pair<BackupRestoreTask, Long> taskWithResult = 157 (Pair<BackupRestoreTask, Long>) msg.obj; 158 taskWithResult.first.operationComplete(taskWithResult.second); 159 } catch (ClassCastException e) { 160 Slog.e(RefactoredBackupManagerService.TAG, "Invalid completion in flight, obj=" + msg.obj); 161 } 162 break; 163 } 164 165 case RefactoredBackupManagerService.MSG_RUN_ADB_BACKUP: { 166 // TODO: refactor full backup to be a looper-based state machine 167 // similar to normal backup/restore. 168 AdbBackupParams params = (AdbBackupParams) msg.obj; 169 PerformAdbBackupTask task = new PerformAdbBackupTask(backupManagerService, params.fd, 170 params.observer, params.includeApks, params.includeObbs, 171 params.includeShared, params.doWidgets, params.curPassword, 172 params.encryptPassword, params.allApps, params.includeSystem, 173 params.doCompress, params.includeKeyValue, params.packages, params.latch); 174 (new Thread(task, "adb-backup")).start(); 175 break; 176 } 177 178 case RefactoredBackupManagerService.MSG_RUN_FULL_TRANSPORT_BACKUP: { 179 PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj; 180 (new Thread(task, "transport-backup")).start(); 181 break; 182 } 183 184 case RefactoredBackupManagerService.MSG_RUN_RESTORE: { 185 RestoreParams params = (RestoreParams) msg.obj; 186 Slog.d(RefactoredBackupManagerService.TAG, "MSG_RUN_RESTORE observer=" + params.observer); 187 188 PerformUnifiedRestoreTask task = new PerformUnifiedRestoreTask(backupManagerService, params.transport, 189 params.observer, params.monitor, params.token, params.pkgInfo, 190 params.pmToken, params.isSystemRestore, params.filterSet); 191 192 synchronized (backupManagerService.mPendingRestores) { 193 if (backupManagerService.mIsRestoreInProgress) { 194 if (RefactoredBackupManagerService.DEBUG) { 195 Slog.d(RefactoredBackupManagerService.TAG, "Restore in progress, queueing."); 196 } 197 backupManagerService.mPendingRestores.add(task); 198 // This task will be picked up and executed when the the currently running 199 // restore task finishes. 200 } else { 201 if (RefactoredBackupManagerService.DEBUG) { 202 Slog.d(RefactoredBackupManagerService.TAG, "Starting restore."); 203 } 204 backupManagerService.mIsRestoreInProgress = true; 205 Message restoreMsg = obtainMessage( 206 RefactoredBackupManagerService.MSG_BACKUP_RESTORE_STEP, task); 207 sendMessage(restoreMsg); 208 } 209 } 210 break; 211 } 212 213 case RefactoredBackupManagerService.MSG_RUN_ADB_RESTORE: { 214 // TODO: refactor full restore to be a looper-based state machine 215 // similar to normal backup/restore. 216 AdbRestoreParams params = (AdbRestoreParams) msg.obj; 217 PerformAdbRestoreTask task = new PerformAdbRestoreTask(backupManagerService, params.fd, 218 params.curPassword, params.encryptPassword, 219 params.observer, params.latch); 220 (new Thread(task, "adb-restore")).start(); 221 break; 222 } 223 224 case RefactoredBackupManagerService.MSG_RUN_CLEAR: { 225 ClearParams params = (ClearParams) msg.obj; 226 (new PerformClearTask(backupManagerService, params.transport, params.packageInfo)).run(); 227 break; 228 } 229 230 case RefactoredBackupManagerService.MSG_RETRY_CLEAR: { 231 // reenqueues if the transport remains unavailable 232 ClearRetryParams params = (ClearRetryParams) msg.obj; 233 backupManagerService.clearBackupData(params.transportName, params.packageName); 234 break; 235 } 236 237 case RefactoredBackupManagerService.MSG_RUN_INITIALIZE: { 238 HashSet<String> queue; 239 240 // Snapshot the pending-init queue and work on that 241 synchronized (backupManagerService.mQueueLock) { 242 queue = new HashSet<>(backupManagerService.mPendingInits); 243 backupManagerService.mPendingInits.clear(); 244 } 245 246 (new PerformInitializeTask(backupManagerService, queue)).run(); 247 break; 248 } 249 250 case RefactoredBackupManagerService.MSG_RETRY_INIT: { 251 synchronized (backupManagerService.mQueueLock) { 252 backupManagerService.recordInitPendingLocked(msg.arg1 != 0, (String) msg.obj); 253 backupManagerService.mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 254 backupManagerService.mRunInitIntent); 255 } 256 break; 257 } 258 259 case RefactoredBackupManagerService.MSG_RUN_GET_RESTORE_SETS: { 260 // Like other async operations, this is entered with the wakelock held 261 RestoreSet[] sets = null; 262 RestoreGetSetsParams params = (RestoreGetSetsParams) msg.obj; 263 try { 264 sets = params.transport.getAvailableRestoreSets(); 265 // cache the result in the active session 266 synchronized (params.session) { 267 params.session.mRestoreSets = sets; 268 } 269 if (sets == null) { 270 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); 271 } 272 } catch (Exception e) { 273 Slog.e(RefactoredBackupManagerService.TAG, "Error from transport getting set list: " + e.getMessage()); 274 } finally { 275 if (params.observer != null) { 276 try { 277 params.observer.restoreSetsAvailable(sets); 278 } catch (RemoteException re) { 279 Slog.e(RefactoredBackupManagerService.TAG, "Unable to report listing to observer"); 280 } catch (Exception e) { 281 Slog.e(RefactoredBackupManagerService.TAG, "Restore observer threw: " + e.getMessage()); 282 } 283 } 284 285 // Done: reset the session timeout clock 286 removeMessages(RefactoredBackupManagerService.MSG_RESTORE_SESSION_TIMEOUT); 287 sendEmptyMessageDelayed(RefactoredBackupManagerService.MSG_RESTORE_SESSION_TIMEOUT, 288 RefactoredBackupManagerService.TIMEOUT_RESTORE_INTERVAL); 289 290 backupManagerService.mWakelock.release(); 291 } 292 break; 293 } 294 295 case RefactoredBackupManagerService.MSG_BACKUP_OPERATION_TIMEOUT: 296 case RefactoredBackupManagerService.MSG_RESTORE_OPERATION_TIMEOUT: { 297 Slog.d(RefactoredBackupManagerService.TAG, 298 "Timeout message received for token=" + Integer.toHexString(msg.arg1)); 299 backupManagerService.handleCancel(msg.arg1, false); 300 break; 301 } 302 303 case RefactoredBackupManagerService.MSG_RESTORE_SESSION_TIMEOUT: { 304 synchronized (backupManagerService) { 305 if (backupManagerService.mActiveRestoreSession != null) { 306 // Client app left the restore session dangling. We know that it 307 // can't be in the middle of an actual restore operation because 308 // the timeout is suspended while a restore is in progress. Clean 309 // up now. 310 Slog.w(RefactoredBackupManagerService.TAG, "Restore session timed out; aborting"); 311 backupManagerService.mActiveRestoreSession.markTimedOut(); 312 post(backupManagerService.mActiveRestoreSession.new EndRestoreRunnable( 313 backupManagerService, backupManagerService.mActiveRestoreSession)); 314 } 315 } 316 break; 317 } 318 319 case RefactoredBackupManagerService.MSG_FULL_CONFIRMATION_TIMEOUT: { 320 synchronized (backupManagerService.mAdbBackupRestoreConfirmations) { 321 AdbParams params = backupManagerService.mAdbBackupRestoreConfirmations.get(msg.arg1); 322 if (params != null) { 323 Slog.i(RefactoredBackupManagerService.TAG, 324 "Full backup/restore timed out waiting for user confirmation"); 325 326 // Release the waiter; timeout == completion 327 backupManagerService.signalAdbBackupRestoreCompletion(params); 328 329 // Remove the token from the set 330 backupManagerService.mAdbBackupRestoreConfirmations.delete(msg.arg1); 331 332 // Report a timeout to the observer, if any 333 if (params.observer != null) { 334 try { 335 params.observer.onTimeout(); 336 } catch (RemoteException e) { 337 /* don't care if the app has gone away */ 338 } 339 } 340 } else { 341 Slog.d(RefactoredBackupManagerService.TAG, "couldn't find params for token " + msg.arg1); 342 } 343 } 344 break; 345 } 346 347 case RefactoredBackupManagerService.MSG_WIDGET_BROADCAST: { 348 final Intent intent = (Intent) msg.obj; 349 backupManagerService.mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); 350 break; 351 } 352 353 case RefactoredBackupManagerService.MSG_REQUEST_BACKUP: { 354 BackupParams params = (BackupParams) msg.obj; 355 if (RefactoredBackupManagerService.MORE_DEBUG) { 356 Slog.d(RefactoredBackupManagerService.TAG, "MSG_REQUEST_BACKUP observer=" + params.observer); 357 } 358 ArrayList<BackupRequest> kvQueue = new ArrayList<>(); 359 for (String packageName : params.kvPackages) { 360 kvQueue.add(new BackupRequest(packageName)); 361 } 362 backupManagerService.mBackupRunning = true; 363 backupManagerService.mWakelock.acquire(); 364 365 PerformBackupTask pbt = new PerformBackupTask( 366 backupManagerService, 367 params.transport, params.dirName, 368 kvQueue, null, params.observer, params.monitor, params.fullPackages, true, 369 params.nonIncrementalBackup); 370 Message pbtMessage = obtainMessage( 371 RefactoredBackupManagerService.MSG_BACKUP_RESTORE_STEP, pbt); 372 sendMessage(pbtMessage); 373 break; 374 } 375 376 case RefactoredBackupManagerService.MSG_SCHEDULE_BACKUP_PACKAGE: { 377 String pkgName = (String) msg.obj; 378 if (RefactoredBackupManagerService.MORE_DEBUG) { 379 Slog.d(RefactoredBackupManagerService.TAG, "MSG_SCHEDULE_BACKUP_PACKAGE " + pkgName); 380 } 381 backupManagerService.dataChangedImpl(pkgName); 382 break; 383 } 384 } 385 } 386} 387