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.app.backup.RestoreSet;
     20 import android.app.backup.IBackupManager;
     21 import android.app.backup.IRestoreObserver;
     22 import android.app.backup.IRestoreSession;
     23 import android.os.RemoteException;
     24 import android.os.ServiceManager;
     25 
     26 import java.util.HashSet;
     27 
     28 public final class Bmgr {
     29     IBackupManager mBmgr;
     30     IRestoreSession mRestore;
     31 
     32     static final String BMGR_NOT_RUNNING_ERR =
     33             "Error: Could not access the Backup Manager.  Is the system running?";
     34     static final String TRANSPORT_NOT_RUNNING_ERR =
     35         "Error: Could not access the backup transport.  Is the system running?";
     36 
     37     private String[] mArgs;
     38     private int mNextArg;
     39 
     40     public static void main(String[] args) {
     41         try {
     42             new Bmgr().run(args);
     43         } catch (Exception e) {
     44             System.err.println("Exception caught:");
     45             e.printStackTrace();
     46         }
     47     }
     48 
     49     public void run(String[] args) {
     50         if (args.length < 1) {
     51             showUsage();
     52             return;
     53         }
     54 
     55         mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
     56         if (mBmgr == null) {
     57             System.err.println(BMGR_NOT_RUNNING_ERR);
     58             return;
     59         }
     60 
     61         mArgs = args;
     62         String op = args[0];
     63         mNextArg = 1;
     64 
     65         if ("enabled".equals(op)) {
     66             doEnabled();
     67             return;
     68         }
     69 
     70         if ("enable".equals(op)) {
     71             doEnable();
     72             return;
     73         }
     74 
     75         if ("run".equals(op)) {
     76             doRun();
     77             return;
     78         }
     79 
     80         if ("backup".equals(op)) {
     81             doBackup();
     82             return;
     83         }
     84 
     85         if ("list".equals(op)) {
     86             doList();
     87             return;
     88         }
     89 
     90         if ("restore".equals(op)) {
     91             doRestore();
     92             return;
     93         }
     94 
     95         if ("transport".equals(op)) {
     96             doTransport();
     97             return;
     98         }
     99 
    100         if ("wipe".equals(op)) {
    101             doWipe();
    102             return;
    103         }
    104 
    105         System.err.println("Unknown command");
    106         showUsage();
    107     }
    108 
    109     private String enableToString(boolean enabled) {
    110         return enabled ? "enabled" : "disabled";
    111     }
    112 
    113     private void doEnabled() {
    114         try {
    115             boolean isEnabled = mBmgr.isBackupEnabled();
    116             System.out.println("Backup Manager currently "
    117                     + enableToString(isEnabled));
    118         } catch (RemoteException e) {
    119             System.err.println(e.toString());
    120             System.err.println(BMGR_NOT_RUNNING_ERR);
    121         }
    122     }
    123 
    124     private void doEnable() {
    125         String arg = nextArg();
    126         if (arg == null) {
    127             showUsage();
    128             return;
    129         }
    130 
    131         try {
    132             boolean enable = Boolean.parseBoolean(arg);
    133             mBmgr.setBackupEnabled(enable);
    134             System.out.println("Backup Manager now " + enableToString(enable));
    135         } catch (NumberFormatException e) {
    136             showUsage();
    137             return;
    138         } catch (RemoteException e) {
    139             System.err.println(e.toString());
    140             System.err.println(BMGR_NOT_RUNNING_ERR);
    141         }
    142     }
    143 
    144     private void doRun() {
    145         try {
    146             mBmgr.backupNow();
    147         } catch (RemoteException e) {
    148             System.err.println(e.toString());
    149             System.err.println(BMGR_NOT_RUNNING_ERR);
    150         }
    151     }
    152 
    153     private void doBackup() {
    154         String pkg = nextArg();
    155         if (pkg == null) {
    156             showUsage();
    157             return;
    158         }
    159 
    160         try {
    161             mBmgr.dataChanged(pkg);
    162         } catch (RemoteException e) {
    163             System.err.println(e.toString());
    164             System.err.println(BMGR_NOT_RUNNING_ERR);
    165         }
    166     }
    167 
    168     private void doTransport() {
    169         try {
    170             String which = nextArg();
    171             if (which == null) {
    172                 showUsage();
    173                 return;
    174             }
    175 
    176             String old = mBmgr.selectBackupTransport(which);
    177             if (old == null) {
    178                 System.out.println("Unknown transport '" + which
    179                         + "' specified; no changes made.");
    180             } else {
    181                 System.out.println("Selected transport " + which + " (formerly " + old + ")");
    182             }
    183         } catch (RemoteException e) {
    184             System.err.println(e.toString());
    185             System.err.println(BMGR_NOT_RUNNING_ERR);
    186         }
    187     }
    188 
    189     private void doWipe() {
    190         String pkg = nextArg();
    191         if (pkg == null) {
    192             showUsage();
    193             return;
    194         }
    195 
    196         try {
    197             mBmgr.clearBackupData(pkg);
    198             System.out.println("Wiped backup data for " + pkg);
    199         } catch (RemoteException e) {
    200             System.err.println(e.toString());
    201             System.err.println(BMGR_NOT_RUNNING_ERR);
    202         }
    203     }
    204 
    205     private void doList() {
    206         String arg = nextArg();     // sets, transports, packages set#
    207         if ("transports".equals(arg)) {
    208             doListTransports();
    209             return;
    210         }
    211 
    212         // The rest of the 'list' options work with a restore session on the current transport
    213         try {
    214             mRestore = mBmgr.beginRestoreSession(null, null);
    215             if (mRestore == null) {
    216                 System.err.println(BMGR_NOT_RUNNING_ERR);
    217                 return;
    218             }
    219 
    220             if ("sets".equals(arg)) {
    221                 doListRestoreSets();
    222             } else if ("transports".equals(arg)) {
    223                 doListTransports();
    224             }
    225 
    226             mRestore.endRestoreSession();
    227         } catch (RemoteException e) {
    228             System.err.println(e.toString());
    229             System.err.println(BMGR_NOT_RUNNING_ERR);
    230         }
    231     }
    232 
    233     private void doListTransports() {
    234         try {
    235             String current = mBmgr.getCurrentTransport();
    236             String[] transports = mBmgr.listAllTransports();
    237             if (transports == null || transports.length == 0) {
    238                 System.out.println("No transports available.");
    239                 return;
    240             }
    241 
    242             for (String t : transports) {
    243                 String pad = (t.equals(current)) ? "  * " : "    ";
    244                 System.out.println(pad + t);
    245             }
    246         } catch (RemoteException e) {
    247             System.err.println(e.toString());
    248             System.err.println(BMGR_NOT_RUNNING_ERR);
    249         }
    250     }
    251 
    252     private void doListRestoreSets() {
    253         try {
    254             RestoreObserver observer = new RestoreObserver();
    255             int err = mRestore.getAvailableRestoreSets(observer);
    256             if (err != 0) {
    257                 System.out.println("Unable to request restore sets");
    258             } else {
    259                 observer.waitForCompletion();
    260                 printRestoreSets(observer.sets);
    261             }
    262         } catch (RemoteException e) {
    263             System.err.println(e.toString());
    264             System.err.println(TRANSPORT_NOT_RUNNING_ERR);
    265         }
    266     }
    267 
    268     private void printRestoreSets(RestoreSet[] sets) {
    269         if (sets == null || sets.length == 0) {
    270             System.out.println("No restore sets");
    271             return;
    272         }
    273         for (RestoreSet s : sets) {
    274             System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
    275         }
    276     }
    277 
    278     class RestoreObserver extends IRestoreObserver.Stub {
    279         boolean done;
    280         RestoreSet[] sets = null;
    281 
    282         public void restoreSetsAvailable(RestoreSet[] result) {
    283             synchronized (this) {
    284                 sets = result;
    285                 done = true;
    286                 this.notify();
    287             }
    288         }
    289 
    290         public void restoreStarting(int numPackages) {
    291             System.out.println("restoreStarting: " + numPackages + " packages");
    292         }
    293 
    294         public void onUpdate(int nowBeingRestored, String currentPackage) {
    295             System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage);
    296         }
    297 
    298         public void restoreFinished(int error) {
    299             System.out.println("restoreFinished: " + error);
    300             synchronized (this) {
    301                 done = true;
    302                 this.notify();
    303             }
    304         }
    305 
    306         public void waitForCompletion() {
    307             // The restoreFinished() callback will throw the 'done' flag; we
    308             // just sit and wait on that notification.
    309             synchronized (this) {
    310                 while (!this.done) {
    311                     try {
    312                         this.wait();
    313                     } catch (InterruptedException ex) {
    314                     }
    315                 }
    316             }
    317         }
    318     }
    319 
    320     private void doRestore() {
    321         String arg = nextArg();
    322         if (arg == null) {
    323             showUsage();
    324             return;
    325         }
    326 
    327         if (arg.indexOf('.') >= 0) {
    328             // it's a package name
    329             doRestorePackage(arg);
    330         } else {
    331             try {
    332                 long token = Long.parseLong(arg, 16);
    333                 HashSet<String> filter = null;
    334                 while ((arg = nextArg()) != null) {
    335                     if (filter == null) filter = new HashSet<String>();
    336                     filter.add(arg);
    337                 }
    338 
    339                 doRestoreAll(token, filter);
    340             } catch (NumberFormatException e) {
    341                 showUsage();
    342                 return;
    343             }
    344         }
    345 
    346         System.out.println("done");
    347     }
    348 
    349     private void doRestorePackage(String pkg) {
    350         try {
    351             mRestore = mBmgr.beginRestoreSession(pkg, null);
    352             if (mRestore == null) {
    353                 System.err.println(BMGR_NOT_RUNNING_ERR);
    354                 return;
    355             }
    356 
    357             RestoreObserver observer = new RestoreObserver();
    358             int err = mRestore.restorePackage(pkg, observer);
    359             if (err == 0) {
    360                 // Off and running -- wait for the restore to complete
    361                 observer.waitForCompletion();
    362             } else {
    363                 System.err.println("Unable to restore package " + pkg);
    364             }
    365 
    366             // And finally shut down the session
    367             mRestore.endRestoreSession();
    368         } catch (RemoteException e) {
    369             System.err.println(e.toString());
    370             System.err.println(BMGR_NOT_RUNNING_ERR);
    371         }
    372     }
    373 
    374     private void doRestoreAll(long token, HashSet<String> filter) {
    375         RestoreObserver observer = new RestoreObserver();
    376 
    377         try {
    378             boolean didRestore = false;
    379             mRestore = mBmgr.beginRestoreSession(null, null);
    380             if (mRestore == null) {
    381                 System.err.println(BMGR_NOT_RUNNING_ERR);
    382                 return;
    383             }
    384             RestoreSet[] sets = null;
    385             int err = mRestore.getAvailableRestoreSets(observer);
    386             if (err == 0) {
    387                 observer.waitForCompletion();
    388                 sets = observer.sets;
    389                 if (sets != null) {
    390                     for (RestoreSet s : sets) {
    391                         if (s.token == token) {
    392                             System.out.println("Scheduling restore: " + s.name);
    393                             if (filter == null) {
    394                                 didRestore = (mRestore.restoreAll(token, observer) == 0);
    395                             } else {
    396                                 String[] names = new String[filter.size()];
    397                                 filter.toArray(names);
    398                                 didRestore = (mRestore.restoreSome(token, observer, names) == 0);
    399                             }
    400                             break;
    401                         }
    402                     }
    403                 }
    404             }
    405             if (!didRestore) {
    406                 if (sets == null || sets.length == 0) {
    407                     System.out.println("No available restore sets; no restore performed");
    408                 } else {
    409                     System.out.println("No matching restore set token.  Available sets:");
    410                     printRestoreSets(sets);
    411                 }
    412             }
    413 
    414             // if we kicked off a restore successfully, we have to wait for it
    415             // to complete before we can shut down the restore session safely
    416             if (didRestore) {
    417                 observer.waitForCompletion();
    418             }
    419 
    420             // once the restore has finished, close down the session and we're done
    421             mRestore.endRestoreSession();
    422         } catch (RemoteException e) {
    423             System.err.println(e.toString());
    424             System.err.println(BMGR_NOT_RUNNING_ERR);
    425         }
    426     }
    427 
    428     private String nextArg() {
    429         if (mNextArg >= mArgs.length) {
    430             return null;
    431         }
    432         String arg = mArgs[mNextArg];
    433         mNextArg++;
    434         return arg;
    435     }
    436 
    437     private static void showUsage() {
    438         System.err.println("usage: bmgr [backup|restore|list|transport|run]");
    439         System.err.println("       bmgr backup PACKAGE");
    440         System.err.println("       bmgr enable BOOL");
    441         System.err.println("       bmgr enabled");
    442         System.err.println("       bmgr list transports");
    443         System.err.println("       bmgr list sets");
    444         System.err.println("       bmgr transport WHICH");
    445         System.err.println("       bmgr restore TOKEN");
    446         System.err.println("       bmgr restore TOKEN PACKAGE...");
    447         System.err.println("       bmgr restore PACKAGE");
    448         System.err.println("       bmgr run");
    449         System.err.println("       bmgr wipe PACKAGE");
    450         System.err.println("");
    451         System.err.println("The 'backup' command schedules a backup pass for the named package.");
    452         System.err.println("Note that the backup pass will effectively be a no-op if the package");
    453         System.err.println("does not actually have changed data to store.");
    454         System.err.println("");
    455         System.err.println("The 'enable' command enables or disables the entire backup mechanism.");
    456         System.err.println("If the argument is 'true' it will be enabled, otherwise it will be");
    457         System.err.println("disabled.  When disabled, neither backup or restore operations will");
    458         System.err.println("be performed.");
    459         System.err.println("");
    460         System.err.println("The 'enabled' command reports the current enabled/disabled state of");
    461         System.err.println("the backup mechanism.");
    462         System.err.println("");
    463         System.err.println("The 'list transports' command reports the names of the backup transports");
    464         System.err.println("currently available on the device.  These names can be passed as arguments");
    465         System.err.println("to the 'transport' command.  The currently selected transport is indicated");
    466         System.err.println("with a '*' character.");
    467         System.err.println("");
    468         System.err.println("The 'list sets' command reports the token and name of each restore set");
    469         System.err.println("available to the device via the current transport.");
    470         System.err.println("");
    471         System.err.println("The 'transport' command designates the named transport as the currently");
    472         System.err.println("active one.  This setting is persistent across reboots.");
    473         System.err.println("");
    474         System.err.println("The 'restore' command when given just a restore token initiates a full-system");
    475         System.err.println("restore operation from the currently active transport.  It will deliver");
    476         System.err.println("the restore set designated by the TOKEN argument to each application");
    477         System.err.println("that had contributed data to that restore set.");
    478         System.err.println("");
    479         System.err.println("The 'restore' command when given a token and one or more package names");
    480         System.err.println("initiates a restore operation of just those given packages from the restore");
    481         System.err.println("set designated by the TOKEN argument.  It is effectively the same as the");
    482         System.err.println("'restore' operation supplying only a token, but applies a filter to the");
    483         System.err.println("set of applications to be restored.");
    484         System.err.println("");
    485         System.err.println("The 'restore' command when given just a package name intiates a restore of");
    486         System.err.println("just that one package according to the restore set selection algorithm");
    487         System.err.println("used by the RestoreSession.restorePackage() method.");
    488         System.err.println("");
    489         System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
    490         System.err.println("immediately, without the usual waiting period for batching together");
    491         System.err.println("data changes.");
    492         System.err.println("");
    493         System.err.println("The 'wipe' command causes all backed-up data for the given package to be");
    494         System.err.println("erased from the current transport's storage.  The next backup operation");
    495         System.err.println("that the given application performs will rewrite its entire data set.");
    496     }
    497 }
    498