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