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