Home | History | Annotate | Download | only in bmgr
      1 /*
      2  * Copyright (C) 2009 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.commands.bmgr;
     18 
     19 import android.annotation.IntDef;
     20 import android.annotation.UserIdInt;
     21 import android.app.backup.BackupManager;
     22 import android.app.backup.BackupManagerMonitor;
     23 import android.app.backup.BackupProgress;
     24 import android.app.backup.BackupTransport;
     25 import android.app.backup.IBackupManager;
     26 import android.app.backup.IBackupManagerMonitor;
     27 import android.app.backup.IBackupObserver;
     28 import android.app.backup.IRestoreObserver;
     29 import android.app.backup.IRestoreSession;
     30 import android.app.backup.ISelectBackupTransportCallback;
     31 import android.app.backup.RestoreSet;
     32 import android.content.ComponentName;
     33 import android.content.Context;
     34 import android.content.pm.IPackageManager;
     35 import android.content.pm.PackageInfo;
     36 import android.os.Bundle;
     37 import android.os.RemoteException;
     38 import android.os.ServiceManager;
     39 import android.os.SystemClock;
     40 import android.os.UserHandle;
     41 import android.util.ArraySet;
     42 import android.util.Slog;
     43 
     44 import com.android.internal.annotations.GuardedBy;
     45 import com.android.internal.annotations.VisibleForTesting;
     46 
     47 import java.lang.annotation.Retention;
     48 import java.lang.annotation.RetentionPolicy;
     49 import java.util.ArrayList;
     50 import java.util.Arrays;
     51 import java.util.HashSet;
     52 import java.util.List;
     53 import java.util.Set;
     54 import java.util.concurrent.CountDownLatch;
     55 
     56 /**
     57  * Adb shell command for {@link android.app.backup.IBackupManager}.
     58  */
     59 public class Bmgr {
     60     public static final String TAG = "Bmgr";
     61 
     62     private final IBackupManager mBmgr;
     63     private IRestoreSession mRestore;
     64 
     65     private static final String BMGR_NOT_RUNNING_ERR =
     66             "Error: Could not access the Backup Manager.  Is the system running?";
     67     private static final String TRANSPORT_NOT_RUNNING_ERR =
     68             "Error: Could not access the backup transport.  Is the system running?";
     69     private static final String PM_NOT_RUNNING_ERR =
     70             "Error: Could not access the Package Manager.  Is the system running?";
     71 
     72     private String[] mArgs;
     73     private int mNextArg;
     74 
     75     @VisibleForTesting
     76     Bmgr(IBackupManager bmgr) {
     77         mBmgr = bmgr;
     78     }
     79 
     80     Bmgr() {
     81         mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
     82     }
     83 
     84     public static void main(String[] args) {
     85         try {
     86             new Bmgr().run(args);
     87         } catch (Exception e) {
     88             System.err.println("Exception caught:");
     89             e.printStackTrace();
     90         }
     91     }
     92 
     93     public void run(String[] args) {
     94         if (args.length < 1) {
     95             showUsage();
     96             return;
     97         }
     98 
     99         mArgs = args;
    100         mNextArg = 0;
    101         int userId = parseUserId();
    102         String op = nextArg();
    103         Slog.v(TAG, "Running " + op + " for user:" + userId);
    104 
    105         if (mBmgr == null) {
    106             System.err.println(BMGR_NOT_RUNNING_ERR);
    107             return;
    108         }
    109 
    110         if ("activate".equals(op)) {
    111             doActivateService(userId);
    112             return;
    113         }
    114 
    115         if ("activated".equals(op)) {
    116             doActivated(userId);
    117             return;
    118         }
    119 
    120         if (!isBackupActive(userId)) {
    121             return;
    122         }
    123 
    124         if ("enabled".equals(op)) {
    125             doEnabled(userId);
    126             return;
    127         }
    128 
    129         if ("enable".equals(op)) {
    130             doEnable(userId);
    131             return;
    132         }
    133 
    134         if ("run".equals(op)) {
    135             doRun(userId);
    136             return;
    137         }
    138 
    139         if ("backup".equals(op)) {
    140             doBackup(userId);
    141             return;
    142         }
    143 
    144         if ("init".equals(op)) {
    145             doInit(userId);
    146             return;
    147         }
    148 
    149         if ("list".equals(op)) {
    150             doList(userId);
    151             return;
    152         }
    153 
    154         if ("restore".equals(op)) {
    155             doRestore(userId);
    156             return;
    157         }
    158 
    159         if ("transport".equals(op)) {
    160             doTransport(userId);
    161             return;
    162         }
    163 
    164         if ("wipe".equals(op)) {
    165             doWipe(userId);
    166             return;
    167         }
    168 
    169         if ("fullbackup".equals(op)) {
    170             doFullTransportBackup(userId);
    171             return;
    172         }
    173 
    174         if ("backupnow".equals(op)) {
    175             doBackupNow(userId);
    176             return;
    177         }
    178 
    179         if ("cancel".equals(op)) {
    180             doCancel(userId);
    181             return;
    182         }
    183 
    184         if ("whitelist".equals(op)) {
    185             doPrintWhitelist();
    186             return;
    187         }
    188 
    189         System.err.println("Unknown command");
    190         showUsage();
    191     }
    192 
    193     boolean isBackupActive(@UserIdInt int userId) {
    194         try {
    195             if (!mBmgr.isBackupServiceActive(userId)) {
    196                 System.err.println(BMGR_NOT_RUNNING_ERR);
    197                 return false;
    198             }
    199         } catch (RemoteException e) {
    200             System.err.println(e.toString());
    201             System.err.println(BMGR_NOT_RUNNING_ERR);
    202             return false;
    203         }
    204 
    205         return true;
    206     }
    207 
    208     private String activatedToString(boolean activated) {
    209         return activated ? "activated" : "deactivated";
    210     }
    211 
    212     private void doActivated(@UserIdInt int userId) {
    213         try {
    214             System.out.println("Backup Manager currently "
    215                     + activatedToString(mBmgr.isBackupServiceActive(userId)));
    216         } catch (RemoteException e) {
    217             System.err.println(e.toString());
    218             System.err.println(BMGR_NOT_RUNNING_ERR);
    219         }
    220 
    221     }
    222 
    223     private String enableToString(boolean enabled) {
    224         return enabled ? "enabled" : "disabled";
    225     }
    226 
    227     private void doEnabled(@UserIdInt int userId) {
    228         try {
    229             boolean isEnabled = mBmgr.isBackupEnabledForUser(userId);
    230             System.out.println("Backup Manager currently "
    231                     + enableToString(isEnabled));
    232         } catch (RemoteException e) {
    233             System.err.println(e.toString());
    234             System.err.println(BMGR_NOT_RUNNING_ERR);
    235         }
    236     }
    237 
    238     private void doEnable(@UserIdInt int userId) {
    239         String arg = nextArg();
    240         if (arg == null) {
    241             showUsage();
    242             return;
    243         }
    244 
    245         try {
    246             boolean enable = Boolean.parseBoolean(arg);
    247             mBmgr.setBackupEnabledForUser(userId, enable);
    248             System.out.println("Backup Manager now " + enableToString(enable));
    249         } catch (NumberFormatException e) {
    250             showUsage();
    251             return;
    252         } catch (RemoteException e) {
    253             System.err.println(e.toString());
    254             System.err.println(BMGR_NOT_RUNNING_ERR);
    255         }
    256     }
    257 
    258     void doRun(@UserIdInt int userId) {
    259         try {
    260             mBmgr.backupNowForUser(userId);
    261         } catch (RemoteException e) {
    262             System.err.println(e.toString());
    263             System.err.println(BMGR_NOT_RUNNING_ERR);
    264         }
    265     }
    266 
    267     private void doBackup(@UserIdInt int userId) {
    268         String pkg = nextArg();
    269         if (pkg == null) {
    270             showUsage();
    271             return;
    272         }
    273 
    274         try {
    275             mBmgr.dataChangedForUser(userId, pkg);
    276         } catch (RemoteException e) {
    277             System.err.println(e.toString());
    278             System.err.println(BMGR_NOT_RUNNING_ERR);
    279         }
    280     }
    281 
    282     private void doFullTransportBackup(@UserIdInt int userId) {
    283         System.out.println("Performing full transport backup");
    284 
    285         String pkg;
    286         ArraySet<String> allPkgs = new ArraySet<String>();
    287         while ((pkg = nextArg()) != null) {
    288             allPkgs.add(pkg);
    289         }
    290         if (allPkgs.size() > 0) {
    291             try {
    292                 mBmgr.fullTransportBackupForUser(
    293                         userId, allPkgs.toArray(new String[allPkgs.size()]));
    294             } catch (RemoteException e) {
    295                 System.err.println(e.toString());
    296                 System.err.println(BMGR_NOT_RUNNING_ERR);
    297             }
    298         }
    299     }
    300 
    301     // IBackupObserver generically usable for any backup/init operation
    302     private static abstract class Observer extends IBackupObserver.Stub {
    303         private final Object trigger = new Object();
    304 
    305         @GuardedBy("trigger")
    306         private volatile boolean done = false;
    307 
    308         @Override
    309         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
    310         }
    311 
    312         @Override
    313         public void onResult(String currentPackage, int status) {
    314         }
    315 
    316         @Override
    317         public void backupFinished(int status) {
    318             synchronized (trigger) {
    319                 done = true;
    320                 trigger.notify();
    321             }
    322         }
    323 
    324         public boolean done() {
    325             return this.done;
    326         }
    327 
    328         // Wait forever
    329         public void waitForCompletion() {
    330             waitForCompletion(0);
    331         }
    332 
    333         // Wait for a given time and then give up
    334         public void waitForCompletion(long timeout) {
    335             // The backupFinished() callback will throw the 'done' flag; we
    336             // just sit and wait on that notification.
    337             final long targetTime = SystemClock.elapsedRealtime() + timeout;
    338             synchronized (trigger) {
    339                 // Wait until either we're done, or we've reached a stated positive timeout
    340                 while (!done && (timeout <= 0 || SystemClock.elapsedRealtime() < targetTime)) {
    341                     try {
    342                         trigger.wait(1000L);
    343                     } catch (InterruptedException ex) {
    344                     }
    345                 }
    346             }
    347         }
    348     }
    349 
    350     private static class BackupObserver extends Observer {
    351         @Override
    352         public void onUpdate(String currentPackage, BackupProgress backupProgress) {
    353             super.onUpdate(currentPackage, backupProgress);
    354             System.out.println(
    355                 "Package " + currentPackage + " with progress: " + backupProgress.bytesTransferred
    356                     + "/" + backupProgress.bytesExpected);
    357         }
    358 
    359         @Override
    360         public void onResult(String currentPackage, int status) {
    361             super.onResult(currentPackage, status);
    362             System.out.println("Package " + currentPackage + " with result: "
    363                     + convertBackupStatusToString(status));
    364         }
    365 
    366         @Override
    367         public void backupFinished(int status) {
    368             super.backupFinished(status);
    369             System.out.println("Backup finished with result: "
    370                     + convertBackupStatusToString(status));
    371             if (status == BackupManager.ERROR_BACKUP_CANCELLED) {
    372                 System.out.println("Backups can be cancelled if a backup is already running, check "
    373                                 + "backup dumpsys");
    374             }
    375         }
    376     }
    377 
    378     private static String convertBackupStatusToString(int errorCode) {
    379         switch (errorCode) {
    380             case BackupManager.SUCCESS:
    381                 return "Success";
    382             case BackupManager.ERROR_BACKUP_NOT_ALLOWED:
    383                 return "Backup is not allowed";
    384             case BackupManager.ERROR_PACKAGE_NOT_FOUND:
    385                 return "Package not found";
    386             case BackupManager.ERROR_TRANSPORT_ABORTED:
    387                 return "Transport error";
    388             case BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED:
    389                 return "Transport rejected package because it wasn't able to process it"
    390                         + " at the time";
    391             case BackupManager.ERROR_AGENT_FAILURE:
    392                 return "Agent error";
    393             case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
    394                 return "Size quota exceeded";
    395             case BackupManager.ERROR_BACKUP_CANCELLED:
    396                 return "Backup cancelled";
    397             default:
    398                 return "Unknown error";
    399         }
    400     }
    401 
    402     private void backupNowAllPackages(@UserIdInt int userId, boolean nonIncrementalBackup,
    403             @Monitor int monitorState) {
    404         IPackageManager mPm =
    405                 IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    406         if (mPm == null) {
    407             System.err.println(PM_NOT_RUNNING_ERR);
    408             return;
    409         }
    410         List<PackageInfo> installedPackages = null;
    411         try {
    412             installedPackages =  mPm.getInstalledPackages(0, userId).getList();
    413         } catch (RemoteException e) {
    414             System.err.println(e.toString());
    415             System.err.println(PM_NOT_RUNNING_ERR);
    416         }
    417         if (installedPackages != null) {
    418             String[] packages =
    419                     installedPackages.stream().map(p -> p.packageName).toArray(String[]::new);
    420             String[] filteredPackages = {};
    421             try {
    422                 filteredPackages = mBmgr.filterAppsEligibleForBackupForUser(userId, packages);
    423             } catch (RemoteException e) {
    424                 System.err.println(e.toString());
    425                 System.err.println(BMGR_NOT_RUNNING_ERR);
    426             }
    427             backupNowPackages(userId, Arrays.asList(filteredPackages), nonIncrementalBackup,
    428                     monitorState);
    429         }
    430     }
    431 
    432     private void backupNowPackages(
    433             @UserIdInt int userId,
    434             List<String> packages, boolean nonIncrementalBackup, @Monitor int monitorState) {
    435         int flags = 0;
    436         if (nonIncrementalBackup) {
    437             flags |= BackupManager.FLAG_NON_INCREMENTAL_BACKUP;
    438         }
    439         try {
    440             BackupObserver observer = new BackupObserver();
    441             BackupMonitor monitor =
    442                     (monitorState != Monitor.OFF)
    443                             ? new BackupMonitor(monitorState == Monitor.VERBOSE)
    444                             : null;
    445             int err = mBmgr.requestBackupForUser(
    446                     userId,
    447                     packages.toArray(new String[packages.size()]),
    448                     observer,
    449                     monitor,
    450                     flags);
    451             if (err == 0) {
    452                 // Off and running -- wait for the backup to complete
    453                 observer.waitForCompletion();
    454             } else {
    455                 System.err.println("Unable to run backup");
    456             }
    457         } catch (RemoteException e) {
    458             System.err.println(e.toString());
    459             System.err.println(BMGR_NOT_RUNNING_ERR);
    460         }
    461     }
    462 
    463     private void doBackupNow(@UserIdInt int userId) {
    464         String pkg;
    465         boolean backupAll = false;
    466         boolean nonIncrementalBackup = false;
    467         @Monitor int monitor = Monitor.OFF;
    468         ArrayList<String> allPkgs = new ArrayList<String>();
    469         while ((pkg = nextArg()) != null) {
    470             if (pkg.equals("--all")) {
    471                 backupAll = true;
    472             } else if (pkg.equals("--non-incremental")) {
    473                 nonIncrementalBackup = true;
    474             } else if (pkg.equals("--incremental")) {
    475                 nonIncrementalBackup = false;
    476             } else if (pkg.equals("--monitor")) {
    477                 monitor = Monitor.NORMAL;
    478             } else if (pkg.equals("--monitor-verbose")) {
    479                 monitor = Monitor.VERBOSE;
    480             } else {
    481                 if (!allPkgs.contains(pkg)) {
    482                     allPkgs.add(pkg);
    483                 }
    484             }
    485         }
    486         if (backupAll) {
    487             if (allPkgs.size() == 0) {
    488                 System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") +
    489                         "incremental backup for all packages.");
    490                 backupNowAllPackages(userId, nonIncrementalBackup, monitor);
    491             } else {
    492                 System.err.println("Provide only '--all' flag or list of packages.");
    493             }
    494         } else if (allPkgs.size() > 0) {
    495             System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") +
    496                     "incremental backup for " + allPkgs.size() +" requested packages.");
    497             backupNowPackages(userId, allPkgs, nonIncrementalBackup, monitor);
    498         } else {
    499             System.err.println("Provide '--all' flag or list of packages.");
    500         }
    501     }
    502 
    503     private void doCancel(@UserIdInt int userId) {
    504         String arg = nextArg();
    505         if ("backups".equals(arg)) {
    506             try {
    507                 mBmgr.cancelBackupsForUser(userId);
    508             } catch (RemoteException e) {
    509                 System.err.println(e.toString());
    510                 System.err.println(BMGR_NOT_RUNNING_ERR);
    511             }
    512             return;
    513         }
    514 
    515         System.err.println("Unknown command.");
    516     }
    517 
    518     private void doTransport(@UserIdInt int userId) {
    519         try {
    520             String which = nextArg();
    521             if (which == null) {
    522                 showUsage();
    523                 return;
    524             }
    525 
    526             if ("-c".equals(which)) {
    527                 doTransportByComponent(userId);
    528                 return;
    529             }
    530 
    531             String old = mBmgr.selectBackupTransportForUser(userId, which);
    532             if (old == null) {
    533                 System.out.println("Unknown transport '" + which
    534                         + "' specified; no changes made.");
    535             } else {
    536                 System.out.println("Selected transport " + which + " (formerly " + old + ")");
    537             }
    538 
    539         } catch (RemoteException e) {
    540             System.err.println(e.toString());
    541             System.err.println(BMGR_NOT_RUNNING_ERR);
    542         }
    543     }
    544 
    545     private void doTransportByComponent(@UserIdInt int userId) {
    546         String which = nextArg();
    547         if (which == null) {
    548             showUsage();
    549             return;
    550         }
    551 
    552         final CountDownLatch latch = new CountDownLatch(1);
    553 
    554         try {
    555             mBmgr.selectBackupTransportAsyncForUser(
    556                     userId,
    557                     ComponentName.unflattenFromString(which),
    558                     new ISelectBackupTransportCallback.Stub() {
    559                         @Override
    560                         public void onSuccess(String transportName) {
    561                             System.out.println("Success. Selected transport: " + transportName);
    562                             latch.countDown();
    563                         }
    564 
    565                         @Override
    566                         public void onFailure(int reason) {
    567                             System.err.println("Failure. error=" + reason);
    568                             latch.countDown();
    569                         }
    570                     });
    571         } catch (RemoteException e) {
    572             System.err.println(e.toString());
    573             System.err.println(BMGR_NOT_RUNNING_ERR);
    574             return;
    575         }
    576 
    577         try {
    578             latch.await();
    579         } catch (InterruptedException e) {
    580             System.err.println("Operation interrupted.");
    581         }
    582     }
    583 
    584     private void doWipe(@UserIdInt int userId) {
    585         String transport = nextArg();
    586         if (transport == null) {
    587             showUsage();
    588             return;
    589         }
    590 
    591         String pkg = nextArg();
    592         if (pkg == null) {
    593             showUsage();
    594             return;
    595         }
    596 
    597         try {
    598             mBmgr.clearBackupDataForUser(userId, transport, pkg);
    599             System.out.println("Wiped backup data for " + pkg + " on " + transport);
    600         } catch (RemoteException e) {
    601             System.err.println(e.toString());
    602             System.err.println(BMGR_NOT_RUNNING_ERR);
    603         }
    604     }
    605 
    606     class InitObserver extends Observer {
    607         public int result = BackupTransport.TRANSPORT_ERROR;
    608 
    609         @Override
    610         public void backupFinished(int status) {
    611             super.backupFinished(status);
    612             result = status;
    613         }
    614     }
    615 
    616     private void doInit(@UserIdInt int userId) {
    617         ArraySet<String> transports = new ArraySet<>();
    618         String transport;
    619         while ((transport = nextArg()) != null) {
    620             transports.add(transport);
    621         }
    622         if (transports.size() == 0) {
    623             showUsage();
    624             return;
    625         }
    626 
    627         InitObserver observer = new InitObserver();
    628         try {
    629             System.out.println("Initializing transports: " + transports);
    630             mBmgr.initializeTransportsForUser(
    631                     userId, transports.toArray(new String[transports.size()]), observer);
    632             observer.waitForCompletion(30*1000L);
    633             System.out.println("Initialization result: " + observer.result);
    634         } catch (RemoteException e) {
    635             System.err.println(e.toString());
    636             System.err.println(BMGR_NOT_RUNNING_ERR);
    637         }
    638     }
    639 
    640     private void doList(@UserIdInt int userId) {
    641         String arg = nextArg();     // sets, transports, packages set#
    642         if ("transports".equals(arg)) {
    643             doListTransports(userId);
    644             return;
    645         }
    646 
    647         // The rest of the 'list' options work with a restore session on the current transport
    648         try {
    649             mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
    650             if (mRestore == null) {
    651                 System.err.println(BMGR_NOT_RUNNING_ERR);
    652                 return;
    653             }
    654 
    655             if ("sets".equals(arg)) {
    656                 doListRestoreSets();
    657             }
    658 
    659             mRestore.endRestoreSession();
    660         } catch (RemoteException e) {
    661             System.err.println(e.toString());
    662             System.err.println(BMGR_NOT_RUNNING_ERR);
    663         }
    664     }
    665 
    666     private void doListTransports(@UserIdInt int userId) {
    667         String arg = nextArg();
    668 
    669         try {
    670             if ("-c".equals(arg)) {
    671                 for (ComponentName transport : mBmgr.listAllTransportComponentsForUser(userId)) {
    672                     System.out.println(transport.flattenToShortString());
    673                 }
    674                 return;
    675             }
    676 
    677             String current = mBmgr.getCurrentTransportForUser(userId);
    678             String[] transports = mBmgr.listAllTransportsForUser(userId);
    679             if (transports == null || transports.length == 0) {
    680                 System.out.println("No transports available.");
    681                 return;
    682             }
    683 
    684             for (String t : transports) {
    685                 String pad = (t.equals(current)) ? "  * " : "    ";
    686                 System.out.println(pad + t);
    687             }
    688         } catch (RemoteException e) {
    689             System.err.println(e.toString());
    690             System.err.println(BMGR_NOT_RUNNING_ERR);
    691         }
    692     }
    693 
    694     private void doListRestoreSets() {
    695         try {
    696             RestoreObserver observer = new RestoreObserver();
    697             // TODO implement monitor here
    698             int err = mRestore.getAvailableRestoreSets(observer, null);
    699             if (err != 0) {
    700                 System.out.println("Unable to request restore sets");
    701             } else {
    702                 observer.waitForCompletion();
    703                 printRestoreSets(observer.sets);
    704             }
    705         } catch (RemoteException e) {
    706             System.err.println(e.toString());
    707             System.err.println(TRANSPORT_NOT_RUNNING_ERR);
    708         }
    709     }
    710 
    711     private void printRestoreSets(RestoreSet[] sets) {
    712         if (sets == null || sets.length == 0) {
    713             System.out.println("No restore sets");
    714             return;
    715         }
    716         for (RestoreSet s : sets) {
    717             System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
    718         }
    719     }
    720 
    721     class RestoreObserver extends IRestoreObserver.Stub {
    722         boolean done;
    723         RestoreSet[] sets = null;
    724 
    725         public void restoreSetsAvailable(RestoreSet[] result) {
    726             synchronized (this) {
    727                 sets = result;
    728                 done = true;
    729                 this.notify();
    730             }
    731         }
    732 
    733         public void restoreStarting(int numPackages) {
    734             System.out.println("restoreStarting: " + numPackages + " packages");
    735         }
    736 
    737         public void onUpdate(int nowBeingRestored, String currentPackage) {
    738             System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage);
    739         }
    740 
    741         public void restoreFinished(int error) {
    742             System.out.println("restoreFinished: " + error);
    743             synchronized (this) {
    744                 done = true;
    745                 this.notify();
    746             }
    747         }
    748 
    749         /**
    750          * Wait until either {@link #restoreFinished} or {@link #restoreStarting} is called.
    751          * Once one is called, it clears the internal flag again, so that the same observer intance
    752          * can be reused for a next operation.
    753          */
    754         public void waitForCompletion() {
    755             // The restoreFinished() callback will throw the 'done' flag; we
    756             // just sit and wait on that notification.
    757             synchronized (this) {
    758                 while (!this.done) {
    759                     try {
    760                         this.wait();
    761                     } catch (InterruptedException ex) {
    762                     }
    763                 }
    764                 done = false;
    765             }
    766         }
    767     }
    768 
    769     private void doRestore(@UserIdInt int userId) {
    770         String arg = nextArg();
    771         if (arg == null) {
    772             showUsage();
    773             return;
    774         }
    775 
    776         if (arg.indexOf('.') >= 0 || arg.equals("android")) {
    777             // it's a package name
    778             doRestorePackage(arg);
    779         } else {
    780             try {
    781                 long token = Long.parseLong(arg, 16);
    782                 HashSet<String> filter = null;
    783                 while ((arg = nextArg()) != null) {
    784                     if (filter == null) filter = new HashSet<String>();
    785                     filter.add(arg);
    786                 }
    787 
    788                 doRestoreAll(userId, token, filter);
    789             } catch (NumberFormatException e) {
    790                 showUsage();
    791                 return;
    792             }
    793         }
    794     }
    795 
    796     private void doRestorePackage(String pkg) {
    797         System.err.println("The syntax 'restore <package>' is no longer supported, please use ");
    798         System.err.println("'restore <token> <package>'.");
    799     }
    800 
    801     private void doRestoreAll(@UserIdInt int userId, long token, HashSet<String> filter) {
    802         RestoreObserver observer = new RestoreObserver();
    803 
    804         try {
    805             boolean didRestore = false;
    806             mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
    807             if (mRestore == null) {
    808                 System.err.println(BMGR_NOT_RUNNING_ERR);
    809                 return;
    810             }
    811             RestoreSet[] sets = null;
    812             // TODO implement monitor here
    813             int err = mRestore.getAvailableRestoreSets(observer, null);
    814             if (err == 0) {
    815                 observer.waitForCompletion();
    816                 sets = observer.sets;
    817                 if (sets != null) {
    818                     for (RestoreSet s : sets) {
    819                         if (s.token == token) {
    820                             System.out.println("Scheduling restore: " + s.name);
    821                             if (filter == null) {
    822                                 didRestore = (mRestore.restoreAll(token, observer, null) == 0);
    823                             } else {
    824                                 String[] names = new String[filter.size()];
    825                                 filter.toArray(names);
    826                                 didRestore = (mRestore.restorePackages(token, observer, names,
    827                                         null) == 0);
    828                             }
    829                             break;
    830                         }
    831                     }
    832                 }
    833             }
    834             if (!didRestore) {
    835                 if (sets == null || sets.length == 0) {
    836                     System.out.println("No available restore sets; no restore performed");
    837                 } else {
    838                     System.out.println("No matching restore set token.  Available sets:");
    839                     printRestoreSets(sets);
    840                 }
    841             }
    842 
    843             // if we kicked off a restore successfully, we have to wait for it
    844             // to complete before we can shut down the restore session safely
    845             if (didRestore) {
    846                 observer.waitForCompletion();
    847             }
    848 
    849             // once the restore has finished, close down the session and we're done
    850             mRestore.endRestoreSession();
    851 
    852             System.out.println("done");
    853         } catch (RemoteException e) {
    854             System.err.println(e.toString());
    855             System.err.println(BMGR_NOT_RUNNING_ERR);
    856         }
    857     }
    858 
    859     private void doPrintWhitelist() {
    860         try {
    861             final String[] whitelist = mBmgr.getTransportWhitelist();
    862             if (whitelist != null) {
    863                 for (String transport : whitelist) {
    864                     System.out.println(transport);
    865                 }
    866             }
    867         } catch (RemoteException e) {
    868             System.err.println(e.toString());
    869             System.err.println(BMGR_NOT_RUNNING_ERR);
    870         }
    871     }
    872 
    873     private void doActivateService(int userId) {
    874         String arg = nextArg();
    875         if (arg == null) {
    876             showUsage();
    877             return;
    878         }
    879 
    880         try {
    881             boolean activate = Boolean.parseBoolean(arg);
    882             mBmgr.setBackupServiceActive(userId, activate);
    883             System.out.println(
    884                     "Backup service now "
    885                             + (activate ? "activated" : "deactivated")
    886                             + " for user "
    887                             + userId);
    888         } catch (RemoteException e) {
    889             System.err.println(e.toString());
    890             System.err.println(BMGR_NOT_RUNNING_ERR);
    891         }
    892     }
    893 
    894     private String nextArg() {
    895         if (mNextArg >= mArgs.length) {
    896             return null;
    897         }
    898         String arg = mArgs[mNextArg];
    899         mNextArg++;
    900         return arg;
    901     }
    902 
    903     private int parseUserId() {
    904         String arg = nextArg();
    905         if ("--user".equals(arg)) {
    906             return UserHandle.parseUserArg(nextArg());
    907         } else {
    908             mNextArg--;
    909             return UserHandle.USER_SYSTEM;
    910         }
    911     }
    912 
    913     private static void showUsage() {
    914         System.err.println("usage: bmgr [--user <userId>] [backup|restore|list|transport|run]");
    915         System.err.println("       bmgr backup PACKAGE");
    916         System.err.println("       bmgr enable BOOL");
    917         System.err.println("       bmgr enabled");
    918         System.err.println("       bmgr list transports [-c]");
    919         System.err.println("       bmgr list sets");
    920         System.err.println("       bmgr transport WHICH|-c WHICH_COMPONENT");
    921         System.err.println("       bmgr restore TOKEN");
    922         System.err.println("       bmgr restore TOKEN PACKAGE...");
    923         System.err.println("       bmgr run");
    924         System.err.println("       bmgr wipe TRANSPORT PACKAGE");
    925         System.err.println("       bmgr fullbackup PACKAGE...");
    926         System.err.println("       bmgr backupnow [--monitor|--monitor-verbose] --all|PACKAGE...");
    927         System.err.println("       bmgr cancel backups");
    928         System.err.println("       bmgr init TRANSPORT...");
    929         System.err.println("       bmgr activate BOOL");
    930         System.err.println("       bmgr activated");
    931         System.err.println("");
    932         System.err.println("The '--user' option specifies the user on which the operation is run.");
    933         System.err.println("It must be the first argument before the operation.");
    934         System.err.println("The default value is 0 which is the system user.");
    935         System.err.println("");
    936         System.err.println("The 'backup' command schedules a backup pass for the named package.");
    937         System.err.println("Note that the backup pass will effectively be a no-op if the package");
    938         System.err.println("does not actually have changed data to store.");
    939         System.err.println("");
    940         System.err.println("The 'enable' command enables or disables the entire backup mechanism.");
    941         System.err.println("If the argument is 'true' it will be enabled, otherwise it will be");
    942         System.err.println("disabled.  When disabled, neither backup or restore operations will");
    943         System.err.println("be performed.");
    944         System.err.println("");
    945         System.err.println("The 'enabled' command reports the current enabled/disabled state of");
    946         System.err.println("the backup mechanism.");
    947         System.err.println("");
    948         System.err.println("The 'list transports' command reports the names of the backup transports");
    949         System.err.println("BackupManager is currently bound to. These names can be passed as arguments");
    950         System.err.println("to the 'transport' and 'wipe' commands.  The currently active transport");
    951         System.err.println("is indicated with a '*' character. If -c flag is used, all available");
    952         System.err.println("transport components on the device are listed. These can be used with");
    953         System.err.println("the component variant of 'transport' command.");
    954         System.err.println("");
    955         System.err.println("The 'list sets' command reports the token and name of each restore set");
    956         System.err.println("available to the device via the currently active transport.");
    957         System.err.println("");
    958         System.err.println("The 'transport' command designates the named transport as the currently");
    959         System.err.println("active one.  This setting is persistent across reboots. If -c flag is");
    960         System.err.println("specified, the following string is treated as a component name.");
    961         System.err.println("");
    962         System.err.println("The 'restore' command when given just a restore token initiates a full-system");
    963         System.err.println("restore operation from the currently active transport.  It will deliver");
    964         System.err.println("the restore set designated by the TOKEN argument to each application");
    965         System.err.println("that had contributed data to that restore set.");
    966         System.err.println("");
    967         System.err.println("The 'restore' command when given a token and one or more package names");
    968         System.err.println("initiates a restore operation of just those given packages from the restore");
    969         System.err.println("set designated by the TOKEN argument.  It is effectively the same as the");
    970         System.err.println("'restore' operation supplying only a token, but applies a filter to the");
    971         System.err.println("set of applications to be restored.");
    972         System.err.println("");
    973         System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
    974         System.err.println("immediately, without the usual waiting period for batching together");
    975         System.err.println("data changes.");
    976         System.err.println("");
    977         System.err.println("The 'wipe' command causes all backed-up data for the given package to be");
    978         System.err.println("erased from the given transport's storage.  The next backup operation");
    979         System.err.println("that the given application performs will rewrite its entire data set.");
    980         System.err.println("Transport names to use here are those reported by 'list transports'.");
    981         System.err.println("");
    982         System.err.println("The 'fullbackup' command induces a full-data stream backup for one or more");
    983         System.err.println("packages.  The data is sent via the currently active transport.");
    984         System.err.println("");
    985         System.err.println("The 'backupnow' command runs an immediate backup for one or more packages.");
    986         System.err.println("    --all flag runs backup for all eligible packages.");
    987         System.err.println("    --monitor flag prints monitor events.");
    988         System.err.println("    --monitor-verbose flag prints monitor events with all keys.");
    989         System.err.println("For each package it will run key/value or full data backup ");
    990         System.err.println("depending on the package's manifest declarations.");
    991         System.err.println("The data is sent via the currently active transport.");
    992         System.err.println("");
    993         System.err.println("The 'cancel backups' command cancels all running backups.");
    994         System.err.println("");
    995         System.err.println("The 'init' command initializes the given transports, wiping all data");
    996         System.err.println("from their backing data stores.");
    997         System.err.println("");
    998         System.err.println("The 'activate' command activates or deactivates the backup service.");
    999         System.err.println("If the argument is 'true' it will be activated, otherwise it will be");
   1000         System.err.println("deactivated. When deactivated, the service will not be running and no");
   1001         System.err.println("operations can be performed until activation.");
   1002         System.err.println("");
   1003         System.err.println("The 'activated' command reports the current activated/deactivated");
   1004         System.err.println("state of the backup mechanism.");
   1005     }
   1006 
   1007     private static class BackupMonitor extends IBackupManagerMonitor.Stub {
   1008         private final boolean mVerbose;
   1009 
   1010         private BackupMonitor(boolean verbose) {
   1011             mVerbose = verbose;
   1012         }
   1013 
   1014         @Override
   1015         public void onEvent(Bundle event) throws RemoteException {
   1016             StringBuilder out = new StringBuilder();
   1017             int id = event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID);
   1018             int category = event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY);
   1019             out.append("=> Event{").append(eventCategoryToString(category));
   1020             out.append(" / ").append(eventIdToString(id));
   1021             String packageName = event.getString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME);
   1022             if (packageName != null) {
   1023                 out.append(" : package = ").append(packageName);
   1024                 if (event.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)) {
   1025                     long version =
   1026                             event.getLong(
   1027                                     BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION);
   1028                     out.append("(v").append(version).append(")");
   1029                 }
   1030             }
   1031             if (mVerbose) {
   1032                 Set<String> remainingKeys = new ArraySet<>(event.keySet());
   1033                 remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_ID);
   1034                 remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY);
   1035                 remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME);
   1036                 remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION);
   1037                 remainingKeys.remove(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION);
   1038                 if (!remainingKeys.isEmpty()) {
   1039                     out.append(", other keys =");
   1040                     for (String key : remainingKeys) {
   1041                         out.append(" ").append(key);
   1042                     }
   1043                 }
   1044             }
   1045             out.append("}");
   1046             System.out.println(out.toString());
   1047         }
   1048     }
   1049 
   1050     private static String eventCategoryToString(int eventCategory) {
   1051         switch (eventCategory) {
   1052             case BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT:
   1053                 return "TRANSPORT";
   1054             case BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT:
   1055                 return "AGENT";
   1056             case BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY:
   1057                 return "BACKUP_MANAGER_POLICY";
   1058             default:
   1059                 return "UNKNOWN_CATEGORY";
   1060         }
   1061     }
   1062 
   1063     private static String eventIdToString(int eventId) {
   1064         switch (eventId) {
   1065             case BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL:
   1066                 return "FULL_BACKUP_CANCEL";
   1067             case BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY:
   1068                 return "ILLEGAL_KEY";
   1069             case BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND:
   1070                 return "NO_DATA_TO_SEND";
   1071             case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE:
   1072                 return "PACKAGE_INELIGIBLE";
   1073             case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT:
   1074                 return "PACKAGE_KEY_VALUE_PARTICIPANT";
   1075             case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED:
   1076                 return "PACKAGE_STOPPED";
   1077             case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND:
   1078                 return "PACKAGE_NOT_FOUND";
   1079             case BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED:
   1080                 return "BACKUP_DISABLED";
   1081             case BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED:
   1082                 return "DEVICE_NOT_PROVISIONED";
   1083             case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT:
   1084                 return "PACKAGE_TRANSPORT_NOT_PRESENT";
   1085             case BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT:
   1086                 return "ERROR_PREFLIGHT";
   1087             case BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT:
   1088                 return "QUOTA_HIT_PREFLIGHT";
   1089             case BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP:
   1090                 return "EXCEPTION_FULL_BACKUP";
   1091             case BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL:
   1092                 return "KEY_VALUE_BACKUP_CANCEL";
   1093             case BackupManagerMonitor.LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE:
   1094                 return "NO_RESTORE_METADATA_AVAILABLE";
   1095             case BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED:
   1096                 return "NO_PM_METADATA_RECEIVED";
   1097             case BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA:
   1098                 return "PM_AGENT_HAS_NO_METADATA";
   1099             case BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT:
   1100                 return "LOST_TRANSPORT";
   1101             case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_PRESENT:
   1102                 return "PACKAGE_NOT_PRESENT";
   1103             case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER:
   1104                 return "RESTORE_VERSION_HIGHER";
   1105             case BackupManagerMonitor.LOG_EVENT_ID_APP_HAS_NO_AGENT:
   1106                 return "APP_HAS_NO_AGENT";
   1107             case BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH:
   1108                 return "SIGNATURE_MISMATCH";
   1109             case BackupManagerMonitor.LOG_EVENT_ID_CANT_FIND_AGENT:
   1110                 return "CANT_FIND_AGENT";
   1111             case BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT:
   1112                 return "KEY_VALUE_RESTORE_TIMEOUT";
   1113             case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION:
   1114                 return "RESTORE_ANY_VERSION";
   1115             case BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH:
   1116                 return "VERSIONS_MATCH";
   1117             case BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER:
   1118                 return "VERSION_OF_BACKUP_OLDER";
   1119             case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH:
   1120                 return "FULL_RESTORE_SIGNATURE_MISMATCH";
   1121             case BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT:
   1122                 return "SYSTEM_APP_NO_AGENT";
   1123             case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE:
   1124                 return "FULL_RESTORE_ALLOW_BACKUP_FALSE";
   1125             case BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED:
   1126                 return "APK_NOT_INSTALLED";
   1127             case BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK:
   1128                 return "CANNOT_RESTORE_WITHOUT_APK";
   1129             case BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE:
   1130                 return "MISSING_SIGNATURE";
   1131             case BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE:
   1132                 return "EXPECTED_DIFFERENT_PACKAGE";
   1133             case BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION:
   1134                 return "UNKNOWN_VERSION";
   1135             case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_TIMEOUT:
   1136                 return "FULL_RESTORE_TIMEOUT";
   1137             case BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST:
   1138                 return "CORRUPT_MANIFEST";
   1139             case BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH:
   1140                 return "WIDGET_METADATA_MISMATCH";
   1141             case BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION:
   1142                 return "WIDGET_UNKNOWN_VERSION";
   1143             case BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES:
   1144                 return "NO_PACKAGES";
   1145             case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL:
   1146                 return "TRANSPORT_IS_NULL";
   1147             default:
   1148                 return "UNKNOWN_ID";
   1149         }
   1150     }
   1151 
   1152     @IntDef({Monitor.OFF, Monitor.NORMAL, Monitor.VERBOSE})
   1153     @Retention(RetentionPolicy.SOURCE)
   1154     private @interface Monitor {
   1155         int OFF = 0;
   1156         int NORMAL = 1;
   1157         int VERBOSE = 2;
   1158     }
   1159 }
   1160