Bmgr.java revision 4a627c71ff53a4fca1f961f4b1dcc0461df18a06
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        String pkg = nextArg();
154        if (pkg == null) {
155            showUsage();
156            return;
157        }
158
159        try {
160            mBmgr.dataChanged(pkg);
161        } catch (RemoteException e) {
162            System.err.println(e.toString());
163            System.err.println(BMGR_NOT_RUNNING_ERR);
164        }
165    }
166
167    private void doTransport() {
168        try {
169            String which = nextArg();
170            if (which == null) {
171                showUsage();
172                return;
173            }
174
175            String old = mBmgr.selectBackupTransport(which);
176            if (old == null) {
177                System.out.println("Unknown transport '" + which
178                        + "' specified; no changes made.");
179            } else {
180                System.out.println("Selected transport " + which + " (formerly " + old + ")");
181            }
182        } catch (RemoteException e) {
183            System.err.println(e.toString());
184            System.err.println(BMGR_NOT_RUNNING_ERR);
185        }
186    }
187
188    private void doWipe() {
189        String pkg = nextArg();
190        if (pkg == null) {
191            showUsage();
192            return;
193        }
194
195        try {
196            mBmgr.clearBackupData(pkg);
197            System.out.println("Wiped backup data for " + pkg);
198        } catch (RemoteException e) {
199            System.err.println(e.toString());
200            System.err.println(BMGR_NOT_RUNNING_ERR);
201        }
202    }
203
204    private void doList() {
205        String arg = nextArg();     // sets, transports, packages set#
206        if ("transports".equals(arg)) {
207            doListTransports();
208            return;
209        }
210
211        // The rest of the 'list' options work with a restore session on the current transport
212        try {
213            mRestore = mBmgr.beginRestoreSession(null, null);
214            if (mRestore == null) {
215                System.err.println(BMGR_NOT_RUNNING_ERR);
216                return;
217            }
218
219            if ("sets".equals(arg)) {
220                doListRestoreSets();
221            } else if ("transports".equals(arg)) {
222                doListTransports();
223            }
224
225            mRestore.endRestoreSession();
226        } catch (RemoteException e) {
227            System.err.println(e.toString());
228            System.err.println(BMGR_NOT_RUNNING_ERR);
229        }
230    }
231
232    private void doListTransports() {
233        try {
234            String current = mBmgr.getCurrentTransport();
235            String[] transports = mBmgr.listAllTransports();
236            if (transports == null || transports.length == 0) {
237                System.out.println("No transports available.");
238                return;
239            }
240
241            for (String t : transports) {
242                String pad = (t.equals(current)) ? "  * " : "    ";
243                System.out.println(pad + t);
244            }
245        } catch (RemoteException e) {
246            System.err.println(e.toString());
247            System.err.println(BMGR_NOT_RUNNING_ERR);
248        }
249    }
250
251    private void doListRestoreSets() {
252        try {
253            RestoreObserver observer = new RestoreObserver();
254            int err = mRestore.getAvailableRestoreSets(observer);
255            if (err != 0) {
256                System.out.println("Unable to request restore sets");
257            } else {
258                observer.waitForCompletion();
259                printRestoreSets(observer.sets);
260            }
261        } catch (RemoteException e) {
262            System.err.println(e.toString());
263            System.err.println(TRANSPORT_NOT_RUNNING_ERR);
264        }
265    }
266
267    private void printRestoreSets(RestoreSet[] sets) {
268        if (sets == null || sets.length == 0) {
269            System.out.println("No restore sets");
270            return;
271        }
272        for (RestoreSet s : sets) {
273            System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
274        }
275    }
276
277    class RestoreObserver extends IRestoreObserver.Stub {
278        boolean done;
279        RestoreSet[] sets = null;
280
281        public void restoreSetsAvailable(RestoreSet[] result) {
282            synchronized (this) {
283                sets = result;
284                done = true;
285                this.notify();
286            }
287        }
288
289        public void restoreStarting(int numPackages) {
290            System.out.println("restoreStarting: " + numPackages + " packages");
291        }
292
293        public void onUpdate(int nowBeingRestored, String currentPackage) {
294            System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage);
295        }
296
297        public void restoreFinished(int error) {
298            System.out.println("restoreFinished: " + error);
299            synchronized (this) {
300                done = true;
301                this.notify();
302            }
303        }
304
305        public void waitForCompletion() {
306            // The restoreFinished() callback will throw the 'done' flag; we
307            // just sit and wait on that notification.
308            synchronized (this) {
309                while (!this.done) {
310                    try {
311                        this.wait();
312                    } catch (InterruptedException ex) {
313                    }
314                }
315            }
316        }
317    }
318
319    private void doRestore() {
320        String arg = nextArg();
321        if (arg == null) {
322            showUsage();
323            return;
324        }
325
326        if (arg.indexOf('.') >= 0) {
327            // it's a package name
328            doRestorePackage(arg);
329        } else {
330            try {
331                long token = Long.parseLong(arg, 16);
332                doRestoreAll(token);
333            } catch (NumberFormatException e) {
334                showUsage();
335                return;
336            }
337        }
338
339        System.out.println("done");
340    }
341
342    private void doRestorePackage(String pkg) {
343        try {
344            mRestore = mBmgr.beginRestoreSession(pkg, null);
345            if (mRestore == null) {
346                System.err.println(BMGR_NOT_RUNNING_ERR);
347                return;
348            }
349
350            RestoreObserver observer = new RestoreObserver();
351            int err = mRestore.restorePackage(pkg, observer);
352            if (err == 0) {
353                // Off and running -- wait for the restore to complete
354                observer.waitForCompletion();
355            } else {
356                System.err.println("Unable to restore package " + pkg);
357            }
358
359            // And finally shut down the session
360            mRestore.endRestoreSession();
361        } catch (RemoteException e) {
362            System.err.println(e.toString());
363            System.err.println(BMGR_NOT_RUNNING_ERR);
364        }
365    }
366
367    private void doRestoreAll(long token) {
368        RestoreObserver observer = new RestoreObserver();
369
370        try {
371            boolean didRestore = false;
372            mRestore = mBmgr.beginRestoreSession(null, null);
373            if (mRestore == null) {
374                System.err.println(BMGR_NOT_RUNNING_ERR);
375                return;
376            }
377            RestoreSet[] sets = null;
378            int err = mRestore.getAvailableRestoreSets(observer);
379            if (err == 0) {
380                observer.waitForCompletion();
381                sets = observer.sets;
382                if (sets != null) {
383                    for (RestoreSet s : sets) {
384                        if (s.token == token) {
385                            System.out.println("Scheduling restore: " + s.name);
386                            didRestore = (mRestore.restoreAll(token, observer) == 0);
387                            break;
388                        }
389                    }
390                }
391            }
392            if (!didRestore) {
393                if (sets == null || sets.length == 0) {
394                    System.out.println("No available restore sets; no restore performed");
395                } else {
396                    System.out.println("No matching restore set token.  Available sets:");
397                    printRestoreSets(sets);
398                }
399            }
400
401            // if we kicked off a restore successfully, we have to wait for it
402            // to complete before we can shut down the restore session safely
403            if (didRestore) {
404                observer.waitForCompletion();
405            }
406
407            // once the restore has finished, close down the session and we're done
408            mRestore.endRestoreSession();
409        } catch (RemoteException e) {
410            System.err.println(e.toString());
411            System.err.println(BMGR_NOT_RUNNING_ERR);
412        }
413    }
414
415    private String nextArg() {
416        if (mNextArg >= mArgs.length) {
417            return null;
418        }
419        String arg = mArgs[mNextArg];
420        mNextArg++;
421        return arg;
422    }
423
424    private static void showUsage() {
425        System.err.println("usage: bmgr [backup|restore|list|transport|run]");
426        System.err.println("       bmgr backup PACKAGE");
427        System.err.println("       bmgr enable BOOL");
428        System.err.println("       bmgr enabled");
429        System.err.println("       bmgr list transports");
430        System.err.println("       bmgr list sets");
431        System.err.println("       bmgr transport WHICH");
432        System.err.println("       bmgr restore TOKEN");
433        System.err.println("       bmgr restore PACKAGE");
434        System.err.println("       bmgr run");
435        System.err.println("       bmgr wipe PACKAGE");
436        System.err.println("");
437        System.err.println("The 'backup' command schedules a backup pass for the named package.");
438        System.err.println("Note that the backup pass will effectively be a no-op if the package");
439        System.err.println("does not actually have changed data to store.");
440        System.err.println("");
441        System.err.println("The 'enable' command enables or disables the entire backup mechanism.");
442        System.err.println("If the argument is 'true' it will be enabled, otherwise it will be");
443        System.err.println("disabled.  When disabled, neither backup or restore operations will");
444        System.err.println("be performed.");
445        System.err.println("");
446        System.err.println("The 'enabled' command reports the current enabled/disabled state of");
447        System.err.println("the backup mechanism.");
448        System.err.println("");
449        System.err.println("The 'list transports' command reports the names of the backup transports");
450        System.err.println("currently available on the device.  These names can be passed as arguments");
451        System.err.println("to the 'transport' command.  The currently selected transport is indicated");
452        System.err.println("with a '*' character.");
453        System.err.println("");
454        System.err.println("The 'list sets' command reports the token and name of each restore set");
455        System.err.println("available to the device via the current transport.");
456        System.err.println("");
457        System.err.println("The 'transport' command designates the named transport as the currently");
458        System.err.println("active one.  This setting is persistent across reboots.");
459        System.err.println("");
460        System.err.println("The 'restore' command when given a restore token initiates a full-system");
461        System.err.println("restore operation from the currently active transport.  It will deliver");
462        System.err.println("the restore set designated by the TOKEN argument to each application");
463        System.err.println("that had contributed data to that restore set.");
464        System.err.println("");
465        System.err.println("The 'restore' command when given a package name intiates a restore of");
466        System.err.println("just that one package according to the restore set selection algorithm");
467        System.err.println("used by the RestoreSession.restorePackage() method.");
468        System.err.println("");
469        System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
470        System.err.println("immediately, without the usual waiting period for batching together");
471        System.err.println("data changes.");
472        System.err.println("");
473        System.err.println("The 'wipe' command causes all backed-up data for the given package to be");
474        System.err.println("erased from the current transport's storage.  The next backup operation");
475        System.err.println("that the given application performs will rewrite its entire data set.");
476    }
477}
478