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 
17 package com.android.server.backup.fullbackup;
18 
19 import static com.android.server.backup.BackupManagerService.DEBUG;
20 import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
21 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
22 import static com.android.server.backup.UserBackupManagerService.OP_PENDING;
23 import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP;
24 import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT;
25 
26 import android.annotation.Nullable;
27 import android.app.IBackupAgent;
28 import android.app.backup.BackupManager;
29 import android.app.backup.BackupManagerMonitor;
30 import android.app.backup.BackupProgress;
31 import android.app.backup.BackupTransport;
32 import android.app.backup.IBackupManagerMonitor;
33 import android.app.backup.IBackupObserver;
34 import android.app.backup.IFullBackupRestoreObserver;
35 import android.content.pm.PackageInfo;
36 import android.content.pm.PackageManager;
37 import android.content.pm.PackageManager.NameNotFoundException;
38 import android.os.ParcelFileDescriptor;
39 import android.os.RemoteException;
40 import android.util.EventLog;
41 import android.util.Log;
42 import android.util.Slog;
43 
44 import com.android.internal.backup.IBackupTransport;
45 import com.android.internal.util.Preconditions;
46 import com.android.server.EventLogTags;
47 import com.android.server.backup.BackupAgentTimeoutParameters;
48 import com.android.server.backup.BackupRestoreTask;
49 import com.android.server.backup.FullBackupJob;
50 import com.android.server.backup.TransportManager;
51 import com.android.server.backup.UserBackupManagerService;
52 import com.android.server.backup.internal.OnTaskFinishedListener;
53 import com.android.server.backup.internal.Operation;
54 import com.android.server.backup.remote.RemoteCall;
55 import com.android.server.backup.transport.TransportClient;
56 import com.android.server.backup.transport.TransportNotAvailableException;
57 import com.android.server.backup.utils.AppBackupUtils;
58 import com.android.server.backup.utils.BackupManagerMonitorUtils;
59 import com.android.server.backup.utils.BackupObserverUtils;
60 
61 import java.io.FileInputStream;
62 import java.io.FileOutputStream;
63 import java.io.IOException;
64 import java.util.ArrayList;
65 import java.util.concurrent.CountDownLatch;
66 import java.util.concurrent.TimeUnit;
67 import java.util.concurrent.atomic.AtomicLong;
68 
69 /**
70  * Full backup task extension used for transport-oriented operation.
71  *
72  * Flow:
73  * For each requested package:
74  *     - Spin off a new SinglePackageBackupRunner (mBackupRunner) for the current package.
75  *     - Wait until preflight is complete. (mBackupRunner.getPreflightResultBlocking())
76  *     - If preflight data size is within limit, start reading data from agent pipe and writing
77  *       to transport pipe. While there is data to send, call transport.sendBackupData(int) to
78  *       tell the transport how many bytes to expect on its pipe.
79  *     - After sending all data, call transport.finishBackup() if things went well. And
80  *       transport.cancelFullBackup() otherwise.
81  *
82  * Interactions with mCurrentOperations:
83  *     - An entry for this object is added to mCurrentOperations for the entire lifetime of this
84  *       object. Used to cancel the operation.
85  *     - SinglePackageBackupRunner and SinglePackageBackupPreflight will put ephemeral entries
86  *       to get timeouts or operation complete callbacks.
87  *
88  * Handling cancels:
89  *     - The contract we provide is that the task won't interact with the transport after
90  *       handleCancel() is done executing.
91  *     - This task blocks at 3 points: 1. Preflight result check 2. Reading on agent side pipe
92  *       and 3. Get backup result from mBackupRunner.
93  *     - Bubbling up handleCancel to mBackupRunner handles all 3: 1. Calls handleCancel on the
94  *       preflight operation which counts down on the preflight latch. 2. Tears down the agent,
95  *       so read() returns -1. 3. Notifies mCurrentOpLock which unblocks
96  *       mBackupRunner.getBackupResultBlocking().
97  */
98 public class PerformFullTransportBackupTask extends FullBackupTask implements BackupRestoreTask {
newWithCurrentTransport( UserBackupManagerService backupManagerService, IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, IBackupManagerMonitor monitor, boolean userInitiated, String caller)99     public static PerformFullTransportBackupTask newWithCurrentTransport(
100             UserBackupManagerService backupManagerService,
101             IFullBackupRestoreObserver observer,
102             String[] whichPackages,
103             boolean updateSchedule,
104             FullBackupJob runningJob,
105             CountDownLatch latch,
106             IBackupObserver backupObserver,
107             IBackupManagerMonitor monitor,
108             boolean userInitiated,
109             String caller) {
110         TransportManager transportManager = backupManagerService.getTransportManager();
111         TransportClient transportClient = transportManager.getCurrentTransportClient(caller);
112         OnTaskFinishedListener listener =
113                 listenerCaller ->
114                         transportManager.disposeOfTransportClient(transportClient, listenerCaller);
115         return new PerformFullTransportBackupTask(
116                 backupManagerService,
117                 transportClient,
118                 observer,
119                 whichPackages,
120                 updateSchedule,
121                 runningJob,
122                 latch,
123                 backupObserver,
124                 monitor,
125                 listener,
126                 userInitiated);
127     }
128 
129     private static final String TAG = "PFTBT";
130 
131     private UserBackupManagerService backupManagerService;
132     private final Object mCancelLock = new Object();
133 
134     ArrayList<PackageInfo> mPackages;
135     PackageInfo mCurrentPackage;
136     boolean mUpdateSchedule;
137     CountDownLatch mLatch;
138     FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
139     IBackupObserver mBackupObserver;
140     @Nullable private IBackupManagerMonitor mMonitor;
141     boolean mUserInitiated;
142     SinglePackageBackupRunner mBackupRunner;
143     private final int mBackupRunnerOpToken;
144     private final OnTaskFinishedListener mListener;
145     private final TransportClient mTransportClient;
146     private final int mUserId;
147 
148     // This is true when a backup operation for some package is in progress.
149     private volatile boolean mIsDoingBackup;
150     private volatile boolean mCancelAll;
151     private final int mCurrentOpToken;
152     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
153 
PerformFullTransportBackupTask(UserBackupManagerService backupManagerService, TransportClient transportClient, IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver, @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener, boolean userInitiated)154     public PerformFullTransportBackupTask(UserBackupManagerService backupManagerService,
155             TransportClient transportClient,
156             IFullBackupRestoreObserver observer,
157             String[] whichPackages, boolean updateSchedule,
158             FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
159             @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener,
160             boolean userInitiated) {
161         super(observer);
162         this.backupManagerService = backupManagerService;
163         mTransportClient = transportClient;
164         mUpdateSchedule = updateSchedule;
165         mLatch = latch;
166         mJob = runningJob;
167         mPackages = new ArrayList<>(whichPackages.length);
168         mBackupObserver = backupObserver;
169         mMonitor = monitor;
170         mListener = (listener != null) ? listener : OnTaskFinishedListener.NOP;
171         mUserInitiated = userInitiated;
172         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
173         mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken();
174         mAgentTimeoutParameters = Preconditions.checkNotNull(
175                 backupManagerService.getAgentTimeoutParameters(),
176                 "Timeout parameters cannot be null");
177         mUserId = backupManagerService.getUserId();
178 
179         if (backupManagerService.isBackupOperationInProgress()) {
180             if (DEBUG) {
181                 Slog.d(TAG, "Skipping full backup. A backup is already in progress.");
182             }
183             mCancelAll = true;
184             return;
185         }
186 
187         registerTask();
188 
189         for (String pkg : whichPackages) {
190             try {
191                 PackageManager pm = backupManagerService.getPackageManager();
192                 PackageInfo info = pm.getPackageInfoAsUser(pkg,
193                         PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
194                 mCurrentPackage = info;
195                 if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, mUserId)) {
196                     // Cull any packages that have indicated that backups are not permitted,
197                     // that run as system-domain uids but do not define their own backup agents,
198                     // as well as any explicit mention of the 'special' shared-storage agent
199                     // package (we handle that one at the end).
200                     if (MORE_DEBUG) {
201                         Slog.d(TAG, "Ignoring ineligible package " + pkg);
202                     }
203                     mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
204                             BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE,
205                             mCurrentPackage,
206                             BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
207                             null);
208                     BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
209                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
210                     continue;
211                 } else if (!AppBackupUtils.appGetsFullBackup(info)) {
212                     // Cull any packages that are found in the queue but now aren't supposed
213                     // to get full-data backup operations.
214                     if (MORE_DEBUG) {
215                         Slog.d(TAG, "Ignoring full-data backup of key/value participant "
216                                 + pkg);
217                     }
218                     mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
219                             BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT,
220                             mCurrentPackage,
221                             BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
222                             null);
223                     BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
224                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
225                     continue;
226                 } else if (AppBackupUtils.appIsStopped(info.applicationInfo)) {
227                     // Cull any packages in the 'stopped' state: they've either just been
228                     // installed or have explicitly been force-stopped by the user.  In both
229                     // cases we do not want to launch them for backup.
230                     if (MORE_DEBUG) {
231                         Slog.d(TAG, "Ignoring stopped package " + pkg);
232                     }
233                     mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
234                             BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED,
235                             mCurrentPackage,
236                             BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
237                             null);
238                     BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
239                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
240                     continue;
241                 }
242                 mPackages.add(info);
243             } catch (NameNotFoundException e) {
244                 Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
245                 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
246                         BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND,
247                         mCurrentPackage,
248                         BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
249                         null);
250             }
251         }
252     }
253 
registerTask()254     private void registerTask() {
255         synchronized (backupManagerService.getCurrentOpLock()) {
256             Slog.d(TAG, "backupmanager pftbt token=" + Integer.toHexString(mCurrentOpToken));
257             backupManagerService.getCurrentOperations().put(
258                     mCurrentOpToken,
259                     new Operation(OP_PENDING, this, OP_TYPE_BACKUP));
260         }
261     }
262 
unregisterTask()263     public void unregisterTask() {
264         backupManagerService.removeOperation(mCurrentOpToken);
265     }
266 
267     @Override
execute()268     public void execute() {
269         // Nothing to do.
270     }
271 
272     @Override
handleCancel(boolean cancelAll)273     public void handleCancel(boolean cancelAll) {
274         synchronized (mCancelLock) {
275             // We only support 'cancelAll = true' case for this task. Cancelling of a single package
276 
277             // due to timeout is handled by SinglePackageBackupRunner and
278             // SinglePackageBackupPreflight.
279 
280             if (!cancelAll) {
281                 Slog.wtf(TAG, "Expected cancelAll to be true.");
282             }
283 
284             if (mCancelAll) {
285                 Slog.d(TAG, "Ignoring duplicate cancel call.");
286                 return;
287             }
288 
289             mCancelAll = true;
290             if (mIsDoingBackup) {
291                 backupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll);
292                 try {
293                     // If we're running a backup we should be connected to a transport
294                     IBackupTransport transport =
295                             mTransportClient.getConnectedTransport("PFTBT.handleCancel()");
296                     transport.cancelFullBackup();
297                 } catch (RemoteException | TransportNotAvailableException e) {
298                     Slog.w(TAG, "Error calling cancelFullBackup() on transport: " + e);
299                     // Can't do much.
300                 }
301             }
302         }
303     }
304 
305     @Override
operationComplete(long result)306     public void operationComplete(long result) {
307         // Nothing to do.
308     }
309 
310     @Override
run()311     public void run() {
312 
313         // data from the app, passed to us for bridging to the transport
314         ParcelFileDescriptor[] enginePipes = null;
315 
316         // Pipe through which we write data to the transport
317         ParcelFileDescriptor[] transportPipes = null;
318 
319         long backoff = 0;
320         int backupRunStatus = BackupManager.SUCCESS;
321 
322         try {
323             if (!backupManagerService.isEnabled() || !backupManagerService.isSetupComplete()) {
324                 // Backups are globally disabled, so don't proceed.
325                 if (DEBUG) {
326                     Slog.i(TAG, "full backup requested but enabled=" + backupManagerService
327                             .isEnabled()
328                             + " setupComplete=" + backupManagerService.isSetupComplete()
329                             + "; ignoring");
330                 }
331                 int monitoringEvent;
332                 if (backupManagerService.isSetupComplete()) {
333                     monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED;
334                 } else {
335                     monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
336                 }
337                 mMonitor = BackupManagerMonitorUtils
338                         .monitorEvent(mMonitor, monitoringEvent, null,
339                                 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
340                                 null);
341                 mUpdateSchedule = false;
342                 backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
343                 return;
344             }
345 
346             IBackupTransport transport = mTransportClient.connect("PFTBT.run()");
347             if (transport == null) {
348                 Slog.w(TAG, "Transport not present; full data backup not performed");
349                 backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
350                 mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
351                         BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT,
352                         mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
353                         null);
354                 return;
355             }
356 
357             // Set up to send data to the transport
358             final int N = mPackages.size();
359             final byte[] buffer = new byte[8192];
360             for (int i = 0; i < N; i++) {
361                 mBackupRunner = null;
362                 PackageInfo currentPackage = mPackages.get(i);
363                 String packageName = currentPackage.packageName;
364                 if (DEBUG) {
365                     Slog.i(TAG, "Initiating full-data transport backup of " + packageName
366                             + " token: " + mCurrentOpToken);
367                 }
368                 EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName);
369 
370                 transportPipes = ParcelFileDescriptor.createPipe();
371 
372                 // Tell the transport the data's coming
373                 int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
374                 int backupPackageStatus;
375                 long quota = Long.MAX_VALUE;
376                 synchronized (mCancelLock) {
377                     if (mCancelAll) {
378                         break;
379                     }
380                     backupPackageStatus = transport.performFullBackup(currentPackage,
381                             transportPipes[0], flags);
382 
383                     if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
384                         quota = transport.getBackupQuota(currentPackage.packageName,
385                                 true /* isFullBackup */);
386                         // Now set up the backup engine / data source end of things
387                         enginePipes = ParcelFileDescriptor.createPipe();
388                         mBackupRunner =
389                                 new SinglePackageBackupRunner(enginePipes[1], currentPackage,
390                                         mTransportClient, quota, mBackupRunnerOpToken,
391                                         transport.getTransportFlags());
392                         // The runner dup'd the pipe half, so we close it here
393                         enginePipes[1].close();
394                         enginePipes[1] = null;
395 
396                         mIsDoingBackup = true;
397                     }
398                 }
399                 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
400 
401                     // The transport has its own copy of the read end of the pipe,
402                     // so close ours now
403                     transportPipes[0].close();
404                     transportPipes[0] = null;
405 
406                     // Spin off the runner to fetch the app's data and pipe it
407                     // into the engine pipes
408                     (new Thread(mBackupRunner, "package-backup-bridge")).start();
409 
410                     // Read data off the engine pipe and pass it to the transport
411                     // pipe until we hit EOD on the input stream.  We do not take
412                     // close() responsibility for these FDs into these stream wrappers.
413                     FileInputStream in = new FileInputStream(
414                             enginePipes[0].getFileDescriptor());
415                     FileOutputStream out = new FileOutputStream(
416                             transportPipes[1].getFileDescriptor());
417                     long totalRead = 0;
418                     final long preflightResult = mBackupRunner.getPreflightResultBlocking();
419                     // Preflight result is negative if some error happened on preflight.
420                     if (preflightResult < 0) {
421                         if (MORE_DEBUG) {
422                             Slog.d(TAG, "Backup error after preflight of package "
423                                     + packageName + ": " + preflightResult
424                                     + ", not running backup.");
425                         }
426                         mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
427                                 BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT,
428                                 mCurrentPackage,
429                                 BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
430                                 BackupManagerMonitorUtils.putMonitoringExtra(null,
431                                         BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR,
432                                         preflightResult));
433                         backupPackageStatus = (int) preflightResult;
434                     } else {
435                         int nRead = 0;
436                         do {
437                             nRead = in.read(buffer);
438                             if (MORE_DEBUG) {
439                                 Slog.v(TAG, "in.read(buffer) from app: " + nRead);
440                             }
441                             if (nRead > 0) {
442                                 out.write(buffer, 0, nRead);
443                                 synchronized (mCancelLock) {
444                                     if (!mCancelAll) {
445                                         backupPackageStatus = transport.sendBackupData(nRead);
446                                     }
447                                 }
448                                 totalRead += nRead;
449                                 if (mBackupObserver != null && preflightResult > 0) {
450                                     BackupObserverUtils
451                                             .sendBackupOnUpdate(mBackupObserver, packageName,
452                                                     new BackupProgress(preflightResult, totalRead));
453                                 }
454                             }
455                         } while (nRead > 0
456                                 && backupPackageStatus == BackupTransport.TRANSPORT_OK);
457                         // Despite preflight succeeded, package still can hit quota on flight.
458                         if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
459                             Slog.w(TAG, "Package hit quota limit in-flight " + packageName
460                                     + ": " + totalRead + " of " + quota);
461                             mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
462                                     BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT,
463                                     mCurrentPackage,
464                                     BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
465                                     null);
466                             mBackupRunner.sendQuotaExceeded(totalRead, quota);
467                         }
468                     }
469 
470                     final int backupRunnerResult = mBackupRunner.getBackupResultBlocking();
471 
472                     synchronized (mCancelLock) {
473                         mIsDoingBackup = false;
474                         // If mCancelCurrent is true, we have already called cancelFullBackup().
475                         if (!mCancelAll) {
476                             if (backupRunnerResult == BackupTransport.TRANSPORT_OK) {
477                                 // If we were otherwise in a good state, now interpret the final
478                                 // result based on what finishBackup() returns.  If we're in a
479                                 // failure case already, preserve that result and ignore whatever
480                                 // finishBackup() reports.
481                                 final int finishResult = transport.finishBackup();
482                                 if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
483                                     backupPackageStatus = finishResult;
484                                 }
485                             } else {
486                                 transport.cancelFullBackup();
487                             }
488                         }
489                     }
490 
491                     // A transport-originated error here means that we've hit an error that the
492                     // runner doesn't know about, so it's still moving data but we're pulling the
493                     // rug out from under it.  Don't ask for its result:  we already know better
494                     // and we'll hang if we block waiting for it, since it relies on us to
495                     // read back the data it's writing into the engine.  Just proceed with
496                     // a graceful failure.  The runner/engine mechanism will tear itself
497                     // down cleanly when we close the pipes from this end.  Transport-level
498                     // errors take precedence over agent/app-specific errors for purposes of
499                     // determining our course of action.
500                     if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
501                         // We still could fail in backup runner thread.
502                         if (backupRunnerResult != BackupTransport.TRANSPORT_OK) {
503                             // If there was an error in runner thread and
504                             // not TRANSPORT_ERROR here, overwrite it.
505                             backupPackageStatus = backupRunnerResult;
506                         }
507                     } else {
508                         if (MORE_DEBUG) {
509                             Slog.i(TAG, "Transport-level failure; cancelling agent work");
510                         }
511                     }
512 
513                     if (MORE_DEBUG) {
514                         Slog.i(TAG, "Done delivering backup data: result="
515                                 + backupPackageStatus);
516                     }
517 
518                     if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
519                         Slog.e(TAG, "Error " + backupPackageStatus + " backing up "
520                                 + packageName);
521                     }
522 
523                     // Also ask the transport how long it wants us to wait before
524                     // moving on to the next package, if any.
525                     backoff = transport.requestFullBackupTime();
526                     if (DEBUG_SCHEDULING) {
527                         Slog.i(TAG, "Transport suggested backoff=" + backoff);
528                     }
529 
530                 }
531 
532                 // Roll this package to the end of the backup queue if we're
533                 // in a queue-driven mode (regardless of success/failure)
534                 if (mUpdateSchedule) {
535                     backupManagerService.enqueueFullBackup(packageName, System.currentTimeMillis());
536                 }
537 
538                 if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
539                     BackupObserverUtils
540                             .sendBackupOnPackageResult(mBackupObserver, packageName,
541                                     BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
542                     if (DEBUG) {
543                         Slog.i(TAG, "Transport rejected backup of " + packageName
544                                 + ", skipping");
545                     }
546                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE, packageName,
547                             "transport rejected");
548                     // This failure state can come either a-priori from the transport, or
549                     // from the preflight pass.  If we got as far as preflight, we now need
550                     // to tear down the target process.
551                     if (mBackupRunner != null) {
552                         backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
553                     }
554                     // ... and continue looping.
555                 } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
556                     BackupObserverUtils
557                             .sendBackupOnPackageResult(mBackupObserver, packageName,
558                                     BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
559                     if (DEBUG) {
560                         Slog.i(TAG, "Transport quota exceeded for package: " + packageName);
561                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
562                                 packageName);
563                     }
564                     backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
565                     // Do nothing, clean up, and continue looping.
566                 } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) {
567                     BackupObserverUtils
568                             .sendBackupOnPackageResult(mBackupObserver, packageName,
569                                     BackupManager.ERROR_AGENT_FAILURE);
570                     Slog.w(TAG, "Application failure for package: " + packageName);
571                     EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
572                     backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
573                     // Do nothing, clean up, and continue looping.
574                 } else if (backupPackageStatus == BackupManager.ERROR_BACKUP_CANCELLED) {
575                     BackupObserverUtils
576                             .sendBackupOnPackageResult(mBackupObserver, packageName,
577                                     BackupManager.ERROR_BACKUP_CANCELLED);
578                     Slog.w(TAG, "Backup cancelled. package=" + packageName +
579                             ", cancelAll=" + mCancelAll);
580                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName);
581                     backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
582                     // Do nothing, clean up, and continue looping.
583                 } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
584                     BackupObserverUtils
585                             .sendBackupOnPackageResult(mBackupObserver, packageName,
586                                     BackupManager.ERROR_TRANSPORT_ABORTED);
587                     Slog.w(TAG, "Transport failed; aborting backup: " + backupPackageStatus);
588                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
589                     // Abort entire backup pass.
590                     backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
591                     backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
592                     return;
593                 } else {
594                     // Success!
595                     BackupObserverUtils
596                             .sendBackupOnPackageResult(mBackupObserver, packageName,
597                                     BackupManager.SUCCESS);
598                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName);
599                     backupManagerService.logBackupComplete(packageName);
600                 }
601                 cleanUpPipes(transportPipes);
602                 cleanUpPipes(enginePipes);
603                 if (currentPackage.applicationInfo != null) {
604                     Slog.i(TAG, "Unbinding agent in " + packageName);
605                     try {
606                         backupManagerService.getActivityManager().unbindBackupAgent(
607                                 currentPackage.applicationInfo);
608                     } catch (RemoteException e) { /* can't happen; activity manager is local */ }
609                 }
610             }
611         } catch (Exception e) {
612             backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
613             Slog.w(TAG, "Exception trying full transport backup", e);
614             mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
615                     BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP,
616                     mCurrentPackage,
617                     BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
618                     BackupManagerMonitorUtils.putMonitoringExtra(null,
619                             BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP,
620                             Log.getStackTraceString(e)));
621 
622         } finally {
623 
624             if (mCancelAll) {
625                 backupRunStatus = BackupManager.ERROR_BACKUP_CANCELLED;
626             }
627 
628             if (DEBUG) {
629                 Slog.i(TAG, "Full backup completed with status: " + backupRunStatus);
630             }
631             BackupObserverUtils.sendBackupFinished(mBackupObserver, backupRunStatus);
632 
633             cleanUpPipes(transportPipes);
634             cleanUpPipes(enginePipes);
635 
636             unregisterTask();
637 
638             if (mJob != null) {
639                 mJob.finishBackupPass(mUserId);
640             }
641 
642             synchronized (backupManagerService.getQueueLock()) {
643                 backupManagerService.setRunningFullBackupTask(null);
644             }
645 
646             mListener.onFinished("PFTBT.run()");
647 
648             mLatch.countDown();
649 
650             // Now that we're actually done with schedule-driven work, reschedule
651             // the next pass based on the new queue state.
652             if (mUpdateSchedule) {
653                 backupManagerService.scheduleNextFullBackupJob(backoff);
654             }
655 
656             Slog.i(TAG, "Full data backup pass finished.");
657             backupManagerService.getWakelock().release();
658         }
659     }
660 
cleanUpPipes(ParcelFileDescriptor[] pipes)661     void cleanUpPipes(ParcelFileDescriptor[] pipes) {
662         if (pipes != null) {
663             if (pipes[0] != null) {
664                 ParcelFileDescriptor fd = pipes[0];
665                 pipes[0] = null;
666                 try {
667                     fd.close();
668                 } catch (IOException e) {
669                     Slog.w(TAG, "Unable to close pipe!");
670                 }
671             }
672             if (pipes[1] != null) {
673                 ParcelFileDescriptor fd = pipes[1];
674                 pipes[1] = null;
675                 try {
676                     fd.close();
677                 } catch (IOException e) {
678                     Slog.w(TAG, "Unable to close pipe!");
679                 }
680             }
681         }
682     }
683 
684     // Run the backup and pipe it back to the given socket -- expects to run on
685     // a standalone thread.  The  runner owns this half of the pipe, and closes
686     // it to indicate EOD to the other end.
687     class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight {
688         final AtomicLong mResult = new AtomicLong(BackupTransport.AGENT_ERROR);
689         final CountDownLatch mLatch = new CountDownLatch(1);
690         final TransportClient mTransportClient;
691         final long mQuota;
692         private final int mCurrentOpToken;
693         private final int mTransportFlags;
694 
SinglePackageBackupPreflight( TransportClient transportClient, long quota, int currentOpToken, int transportFlags)695         SinglePackageBackupPreflight(
696                 TransportClient transportClient,
697                 long quota,
698                 int currentOpToken,
699                 int transportFlags) {
700             mTransportClient = transportClient;
701             mQuota = quota;
702             mCurrentOpToken = currentOpToken;
703             mTransportFlags = transportFlags;
704         }
705 
706         @Override
preflightFullBackup(PackageInfo pkg, IBackupAgent agent)707         public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) {
708             int result;
709             long fullBackupAgentTimeoutMillis =
710                     mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
711             try {
712                 backupManagerService.prepareOperationTimeout(
713                         mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT);
714                 if (MORE_DEBUG) {
715                     Slog.d(TAG, "Preflighting full payload of " + pkg.packageName);
716                 }
717                 agent.doMeasureFullBackup(mQuota, mCurrentOpToken,
718                         backupManagerService.getBackupManagerBinder(), mTransportFlags);
719 
720                 // Now wait to get our result back.  If this backstop timeout is reached without
721                 // the latch being thrown, flow will continue as though a result or "normal"
722                 // timeout had been produced.  In case of a real backstop timeout, mResult
723                 // will still contain the value it was constructed with, AGENT_ERROR, which
724                 // intentionaly falls into the "just report failure" code.
725                 mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
726 
727                 long totalSize = mResult.get();
728                 // If preflight timed out, mResult will contain error code as int.
729                 if (totalSize < 0) {
730                     return (int) totalSize;
731                 }
732                 if (MORE_DEBUG) {
733                     Slog.v(TAG, "Got preflight response; size=" + totalSize);
734                 }
735 
736                 IBackupTransport transport =
737                         mTransportClient.connectOrThrow("PFTBT$SPBP.preflightFullBackup()");
738                 result = transport.checkFullBackupSize(totalSize);
739                 if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
740                     if (MORE_DEBUG) {
741                         Slog.d(TAG, "Package hit quota limit on preflight " +
742                                 pkg.packageName + ": " + totalSize + " of " + mQuota);
743                     }
744                     RemoteCall.execute(
745                             callback -> agent.doQuotaExceeded(totalSize, mQuota, callback),
746                             mAgentTimeoutParameters.getQuotaExceededTimeoutMillis());
747                 }
748             } catch (Exception e) {
749                 Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage());
750                 result = BackupTransport.AGENT_ERROR;
751             }
752             return result;
753         }
754 
755         @Override
execute()756         public void execute() {
757             // Unused.
758         }
759 
760         @Override
operationComplete(long result)761         public void operationComplete(long result) {
762             // got the callback, and our preflightFullBackup() method is waiting for the result
763             if (MORE_DEBUG) {
764                 Slog.i(TAG, "Preflight op complete, result=" + result);
765             }
766             mResult.set(result);
767             mLatch.countDown();
768             backupManagerService.removeOperation(mCurrentOpToken);
769         }
770 
771         @Override
handleCancel(boolean cancelAll)772         public void handleCancel(boolean cancelAll) {
773             if (MORE_DEBUG) {
774                 Slog.i(TAG, "Preflight cancelled; failing");
775             }
776             mResult.set(BackupTransport.AGENT_ERROR);
777             mLatch.countDown();
778             backupManagerService.removeOperation(mCurrentOpToken);
779         }
780 
781         @Override
getExpectedSizeOrErrorCode()782         public long getExpectedSizeOrErrorCode() {
783             long fullBackupAgentTimeoutMillis =
784                     mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
785             try {
786                 mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
787                 return mResult.get();
788             } catch (InterruptedException e) {
789                 return BackupTransport.NO_MORE_DATA;
790             }
791         }
792     }
793 
794     class SinglePackageBackupRunner implements Runnable, BackupRestoreTask {
795         final ParcelFileDescriptor mOutput;
796         final PackageInfo mTarget;
797         final SinglePackageBackupPreflight mPreflight;
798         final CountDownLatch mPreflightLatch;
799         final CountDownLatch mBackupLatch;
800         private final int mCurrentOpToken;
801         private final int mEphemeralToken;
802         private FullBackupEngine mEngine;
803         private volatile int mPreflightResult;
804         private volatile int mBackupResult;
805         private final long mQuota;
806         private volatile boolean mIsCancelled;
807         private final int mTransportFlags;
808 
SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, TransportClient transportClient, long quota, int currentOpToken, int transportFlags)809         SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
810                 TransportClient transportClient, long quota, int currentOpToken, int transportFlags)
811                 throws IOException {
812             mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
813             mTarget = target;
814             mCurrentOpToken = currentOpToken;
815             mEphemeralToken = backupManagerService.generateRandomIntegerToken();
816             mPreflight = new SinglePackageBackupPreflight(
817                     transportClient, quota, mEphemeralToken, transportFlags);
818             mPreflightLatch = new CountDownLatch(1);
819             mBackupLatch = new CountDownLatch(1);
820             mPreflightResult = BackupTransport.AGENT_ERROR;
821             mBackupResult = BackupTransport.AGENT_ERROR;
822             mQuota = quota;
823             mTransportFlags = transportFlags;
824             registerTask();
825         }
826 
registerTask()827         void registerTask() {
828             synchronized (backupManagerService.getCurrentOpLock()) {
829                 backupManagerService.getCurrentOperations().put(
830                         mCurrentOpToken, new Operation(OP_PENDING, this, OP_TYPE_BACKUP_WAIT));
831             }
832         }
833 
unregisterTask()834         void unregisterTask() {
835             synchronized (backupManagerService.getCurrentOpLock()) {
836                 backupManagerService.getCurrentOperations().remove(mCurrentOpToken);
837             }
838         }
839 
840         @Override
run()841         public void run() {
842             FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
843             mEngine = new FullBackupEngine(backupManagerService, out, mPreflight, mTarget, false,
844                     this, mQuota, mCurrentOpToken, mTransportFlags);
845             try {
846                 try {
847                     if (!mIsCancelled) {
848                         mPreflightResult = mEngine.preflightCheck();
849                     }
850                 } finally {
851                     mPreflightLatch.countDown();
852                 }
853                 // If there is no error on preflight, continue backup.
854                 if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
855                     if (!mIsCancelled) {
856                         mBackupResult = mEngine.backupOnePackage();
857                     }
858                 }
859             } catch (Exception e) {
860                 Slog.e(TAG, "Exception during full package backup of " + mTarget.packageName);
861             } finally {
862                 unregisterTask();
863                 mBackupLatch.countDown();
864                 try {
865                     mOutput.close();
866                 } catch (IOException e) {
867                     Slog.w(TAG, "Error closing transport pipe in runner");
868                 }
869             }
870         }
871 
sendQuotaExceeded(final long backupDataBytes, final long quotaBytes)872         public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
873             mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes);
874         }
875 
876         // If preflight succeeded, returns positive number - preflight size,
877         // otherwise return negative error code.
getPreflightResultBlocking()878         long getPreflightResultBlocking() {
879             long fullBackupAgentTimeoutMillis =
880                     mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
881             try {
882                 mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
883                 if (mIsCancelled) {
884                     return BackupManager.ERROR_BACKUP_CANCELLED;
885                 }
886                 if (mPreflightResult == BackupTransport.TRANSPORT_OK) {
887                     return mPreflight.getExpectedSizeOrErrorCode();
888                 } else {
889                     return mPreflightResult;
890                 }
891             } catch (InterruptedException e) {
892                 return BackupTransport.AGENT_ERROR;
893             }
894         }
895 
getBackupResultBlocking()896         int getBackupResultBlocking() {
897             long fullBackupAgentTimeoutMillis =
898                     mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
899             try {
900                 mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
901                 if (mIsCancelled) {
902                     return BackupManager.ERROR_BACKUP_CANCELLED;
903                 }
904                 return mBackupResult;
905             } catch (InterruptedException e) {
906                 return BackupTransport.AGENT_ERROR;
907             }
908         }
909 
910 
911         // BackupRestoreTask interface: specifically, timeout detection
912 
913         @Override
execute()914         public void execute() { /* intentionally empty */ }
915 
916         @Override
operationComplete(long result)917         public void operationComplete(long result) { /* intentionally empty */ }
918 
919         @Override
handleCancel(boolean cancelAll)920         public void handleCancel(boolean cancelAll) {
921             if (DEBUG) {
922                 Slog.w(TAG, "Full backup cancel of " + mTarget.packageName);
923             }
924 
925             mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
926                     BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL,
927                     mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
928             mIsCancelled = true;
929             // Cancel tasks spun off by this task.
930             backupManagerService.handleCancel(mEphemeralToken, cancelAll);
931             backupManagerService.tearDownAgentAndKill(mTarget.applicationInfo);
932             // Free up everyone waiting on this task and its children.
933             mPreflightLatch.countDown();
934             mBackupLatch.countDown();
935             // We are done with this operation.
936             backupManagerService.removeOperation(mCurrentOpToken);
937         }
938     }
939 }
940