[go: nahoru, domu]

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.BackupManager;
20import android.app.backup.BackupProgress;
21import android.app.backup.RestoreSet;
22import android.app.backup.IBackupManager;
23import android.app.backup.IBackupObserver;
24import android.app.backup.IRestoreObserver;
25import android.app.backup.IRestoreSession;
26import android.content.pm.IPackageManager;
27import android.content.pm.PackageInfo;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.os.UserHandle;
31
32import java.util.ArrayList;
33import java.util.HashSet;
34import java.util.List;
35
36public final class Bmgr {
37    IBackupManager mBmgr;
38    IRestoreSession mRestore;
39
40    static final String BMGR_NOT_RUNNING_ERR =
41            "Error: Could not access the Backup Manager.  Is the system running?";
42    static final String TRANSPORT_NOT_RUNNING_ERR =
43            "Error: Could not access the backup transport.  Is the system running?";
44    static final String PM_NOT_RUNNING_ERR =
45            "Error: Could not access the Package Manager.  Is the system running?";
46
47    private String[] mArgs;
48    private int mNextArg;
49
50    public static void main(String[] args) {
51        try {
52            new Bmgr().run(args);
53        } catch (Exception e) {
54            System.err.println("Exception caught:");
55            e.printStackTrace();
56        }
57    }
58
59    public void run(String[] args) {
60        if (args.length < 1) {
61            showUsage();
62            return;
63        }
64
65        mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
66        if (mBmgr == null) {
67            System.err.println(BMGR_NOT_RUNNING_ERR);
68            return;
69        }
70
71        mArgs = args;
72        String op = args[0];
73        mNextArg = 1;
74
75        if ("enabled".equals(op)) {
76            doEnabled();
77            return;
78        }
79
80        if ("enable".equals(op)) {
81            doEnable();
82            return;
83        }
84
85        if ("run".equals(op)) {
86            doRun();
87            return;
88        }
89
90        if ("backup".equals(op)) {
91            doBackup();
92            return;
93        }
94
95        if ("list".equals(op)) {
96            doList();
97            return;
98        }
99
100        if ("restore".equals(op)) {
101            doRestore();
102            return;
103        }
104
105        if ("transport".equals(op)) {
106            doTransport();
107            return;
108        }
109
110        if ("wipe".equals(op)) {
111            doWipe();
112            return;
113        }
114
115        if ("fullbackup".equals(op)) {
116            doFullTransportBackup();
117            return;
118        }
119
120        if ("backupnow".equals(op)) {
121            doBackupNow();
122            return;
123        }
124
125        if ("whitelist".equals(op)) {
126            doPrintWhitelist();
127            return;
128        }
129
130        System.err.println("Unknown command");
131        showUsage();
132    }
133
134    private String enableToString(boolean enabled) {
135        return enabled ? "enabled" : "disabled";
136    }
137
138    private void doEnabled() {
139        try {
140            boolean isEnabled = mBmgr.isBackupEnabled();
141            System.out.println("Backup Manager currently "
142                    + enableToString(isEnabled));
143        } catch (RemoteException e) {
144            System.err.println(e.toString());
145            System.err.println(BMGR_NOT_RUNNING_ERR);
146        }
147    }
148
149    private void doEnable() {
150        String arg = nextArg();
151        if (arg == null) {
152            showUsage();
153            return;
154        }
155
156        try {
157            boolean enable = Boolean.parseBoolean(arg);
158            mBmgr.setBackupEnabled(enable);
159            System.out.println("Backup Manager now " + enableToString(enable));
160        } catch (NumberFormatException e) {
161            showUsage();
162            return;
163        } catch (RemoteException e) {
164            System.err.println(e.toString());
165            System.err.println(BMGR_NOT_RUNNING_ERR);
166        }
167    }
168
169    private void doRun() {
170        try {
171            mBmgr.backupNow();
172        } catch (RemoteException e) {
173            System.err.println(e.toString());
174            System.err.println(BMGR_NOT_RUNNING_ERR);
175        }
176    }
177
178    private void doBackup() {
179        String pkg = nextArg();
180        if (pkg == null) {
181            showUsage();
182            return;
183        }
184
185        try {
186            mBmgr.dataChanged(pkg);
187        } catch (RemoteException e) {
188            System.err.println(e.toString());
189            System.err.println(BMGR_NOT_RUNNING_ERR);
190        }
191    }
192
193    private void doFullTransportBackup() {
194        System.out.println("Performing full transport backup");
195
196        String pkg;
197        ArrayList<String> allPkgs = new ArrayList<String>();
198        while ((pkg = nextArg()) != null) {
199            allPkgs.add(pkg);
200        }
201        if (allPkgs.size() > 0) {
202            try {
203                mBmgr.fullTransportBackup(allPkgs.toArray(new String[allPkgs.size()]));
204            } catch (RemoteException e) {
205                System.err.println(e.toString());
206                System.err.println(BMGR_NOT_RUNNING_ERR);
207            }
208        }
209    }
210
211    class BackupObserver extends IBackupObserver.Stub {
212        boolean done = false;
213
214        @Override
215        public void onUpdate(String currentPackage, BackupProgress backupProgress) {
216            System.out.println(
217                "Package " + currentPackage + " with progress: " + backupProgress.bytesTransferred
218                    + "/" + backupProgress.bytesExpected);
219        }
220
221        @Override
222        public void onResult(String currentPackage, int status) {
223            System.out.println("Package " + currentPackage + " with result: "
224                    + convertBackupStatusToString(status));
225        }
226
227        @Override
228        public void backupFinished(int status) {
229            System.out.println("Backup finished with result: "
230                    + convertBackupStatusToString(status));
231            synchronized (this) {
232                done = true;
233                this.notify();
234            }
235        }
236
237        public void waitForCompletion() {
238            // The backupFinished() callback will throw the 'done' flag; we
239            // just sit and wait on that notification.
240            synchronized (this) {
241                while (!this.done) {
242                    try {
243                        this.wait();
244                    } catch (InterruptedException ex) {
245                    }
246                }
247            }
248        }
249
250    }
251
252    private static String convertBackupStatusToString(int errorCode) {
253        switch (errorCode) {
254            case BackupManager.SUCCESS:
255                return "Success";
256            case BackupManager.ERROR_BACKUP_NOT_ALLOWED:
257                return "Backup is not allowed";
258            case BackupManager.ERROR_PACKAGE_NOT_FOUND:
259                return "Package not found";
260            case BackupManager.ERROR_TRANSPORT_ABORTED:
261                return "Transport error";
262            case BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED:
263                return "Transport rejected package";
264            case BackupManager.ERROR_AGENT_FAILURE:
265                return "Agent error";
266            case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
267                return "Size quota exceeded";
268            default:
269                return "Unknown error";
270        }
271    }
272
273    private void backupNowAllPackages() {
274        int userId = UserHandle.USER_SYSTEM;
275        IPackageManager mPm =
276                IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
277        if (mPm == null) {
278            System.err.println(PM_NOT_RUNNING_ERR);
279            return;
280        }
281        List<PackageInfo> installedPackages = null;
282        try {
283            installedPackages =  mPm.getInstalledPackages(0, userId).getList();
284        } catch (RemoteException e) {
285            System.err.println(e.toString());
286            System.err.println(PM_NOT_RUNNING_ERR);
287        }
288        if (installedPackages != null) {
289            List<String> packages = new ArrayList<>();
290            for (PackageInfo pi : installedPackages) {
291                try {
292                    if (mBmgr.isAppEligibleForBackup(pi.packageName)) {
293                        packages.add(pi.packageName);
294                    }
295                } catch (RemoteException e) {
296                    System.err.println(e.toString());
297                    System.err.println(BMGR_NOT_RUNNING_ERR);
298                }
299            }
300            backupNowPackages(packages);
301        }
302    }
303
304    private void backupNowPackages(List<String> packages) {
305        try {
306            BackupObserver observer = new BackupObserver();
307            int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer);
308            if (err == 0) {
309                // Off and running -- wait for the backup to complete
310                observer.waitForCompletion();
311            } else {
312                System.err.println("Unable to run backup");
313            }
314        } catch (RemoteException e) {
315            System.err.println(e.toString());
316            System.err.println(BMGR_NOT_RUNNING_ERR);
317        }
318    }
319
320    private void doBackupNow() {
321        String pkg;
322        boolean backupAll = false;
323        ArrayList<String> allPkgs = new ArrayList<String>();
324        while ((pkg = nextArg()) != null) {
325            if (pkg.equals("--all")) {
326                backupAll = true;
327            } else {
328                allPkgs.add(pkg);
329            }
330        }
331        if (backupAll) {
332            if (allPkgs.size() == 0) {
333                System.out.println("Running backup for all packages.");
334                backupNowAllPackages();
335            } else {
336                System.err.println("Provide only '--all' flag or list of packages.");
337            }
338        } else if (allPkgs.size() > 0) {
339            System.out.println("Running backup for " + allPkgs.size() +" requested packages.");
340            backupNowPackages(allPkgs);
341        } else {
342            System.err.println("Provide '--all' flag or list of packages.");
343        }
344    }
345
346    private void doTransport() {
347        try {
348            String which = nextArg();
349            if (which == null) {
350                showUsage();
351                return;
352            }
353
354            String old = mBmgr.selectBackupTransport(which);
355            if (old == null) {
356                System.out.println("Unknown transport '" + which
357                        + "' specified; no changes made.");
358            } else {
359                System.out.println("Selected transport " + which + " (formerly " + old + ")");
360            }
361        } catch (RemoteException e) {
362            System.err.println(e.toString());
363            System.err.println(BMGR_NOT_RUNNING_ERR);
364        }
365    }
366
367    private void doWipe() {
368        String transport = nextArg();
369        if (transport == null) {
370            showUsage();
371            return;
372        }
373
374        String pkg = nextArg();
375        if (pkg == null) {
376            showUsage();
377            return;
378        }
379
380        try {
381            mBmgr.clearBackupData(transport, pkg);
382            System.out.println("Wiped backup data for " + pkg + " on " + transport);
383        } catch (RemoteException e) {
384            System.err.println(e.toString());
385            System.err.println(BMGR_NOT_RUNNING_ERR);
386        }
387    }
388
389    private void doList() {
390        String arg = nextArg();     // sets, transports, packages set#
391        if ("transports".equals(arg)) {
392            doListTransports();
393            return;
394        }
395
396        // The rest of the 'list' options work with a restore session on the current transport
397        try {
398            mRestore = mBmgr.beginRestoreSession(null, null);
399            if (mRestore == null) {
400                System.err.println(BMGR_NOT_RUNNING_ERR);
401                return;
402            }
403
404            if ("sets".equals(arg)) {
405                doListRestoreSets();
406            } else if ("transports".equals(arg)) {
407                doListTransports();
408            }
409
410            mRestore.endRestoreSession();
411        } catch (RemoteException e) {
412            System.err.println(e.toString());
413            System.err.println(BMGR_NOT_RUNNING_ERR);
414        }
415    }
416
417    private void doListTransports() {
418        try {
419            String current = mBmgr.getCurrentTransport();
420            String[] transports = mBmgr.listAllTransports();
421            if (transports == null || transports.length == 0) {
422                System.out.println("No transports available.");
423                return;
424            }
425
426            for (String t : transports) {
427                String pad = (t.equals(current)) ? "  * " : "    ";
428                System.out.println(pad + t);
429            }
430        } catch (RemoteException e) {
431            System.err.println(e.toString());
432            System.err.println(BMGR_NOT_RUNNING_ERR);
433        }
434    }
435
436    private void doListRestoreSets() {
437        try {
438            RestoreObserver observer = new RestoreObserver();
439            int err = mRestore.getAvailableRestoreSets(observer);
440            if (err != 0) {
441                System.out.println("Unable to request restore sets");
442            } else {
443                observer.waitForCompletion();
444                printRestoreSets(observer.sets);
445            }
446        } catch (RemoteException e) {
447            System.err.println(e.toString());
448            System.err.println(TRANSPORT_NOT_RUNNING_ERR);
449        }
450    }
451
452    private void printRestoreSets(RestoreSet[] sets) {
453        if (sets == null || sets.length == 0) {
454            System.out.println("No restore sets");
455            return;
456        }
457        for (RestoreSet s : sets) {
458            System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
459        }
460    }
461
462    class RestoreObserver extends IRestoreObserver.Stub {
463        boolean done;
464        RestoreSet[] sets = null;
465
466        public void restoreSetsAvailable(RestoreSet[] result) {
467            synchronized (this) {
468                sets = result;
469                done = true;
470                this.notify();
471            }
472        }
473
474        public void restoreStarting(int numPackages) {
475            System.out.println("restoreStarting: " + numPackages + " packages");
476        }
477
478        public void onUpdate(int nowBeingRestored, String currentPackage) {
479            System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage);
480        }
481
482        public void restoreFinished(int error) {
483            System.out.println("restoreFinished: " + error);
484            synchronized (this) {
485                done = true;
486                this.notify();
487            }
488        }
489
490        public void waitForCompletion() {
491            // The restoreFinished() callback will throw the 'done' flag; we
492            // just sit and wait on that notification.
493            synchronized (this) {
494                while (!this.done) {
495                    try {
496                        this.wait();
497                    } catch (InterruptedException ex) {
498                    }
499                }
500            }
501        }
502    }
503
504    private void doRestore() {
505        String arg = nextArg();
506        if (arg == null) {
507            showUsage();
508            return;
509        }
510
511        if (arg.indexOf('.') >= 0 || arg.equals("android")) {
512            // it's a package name
513            doRestorePackage(arg);
514        } else {
515            try {
516                long token = Long.parseLong(arg, 16);
517                HashSet<String> filter = null;
518                while ((arg = nextArg()) != null) {
519                    if (filter == null) filter = new HashSet<String>();
520                    filter.add(arg);
521                }
522
523                doRestoreAll(token, filter);
524            } catch (NumberFormatException e) {
525                showUsage();
526                return;
527            }
528        }
529
530        System.out.println("done");
531    }
532
533    private void doRestorePackage(String pkg) {
534        try {
535            mRestore = mBmgr.beginRestoreSession(pkg, null);
536            if (mRestore == null) {
537                System.err.println(BMGR_NOT_RUNNING_ERR);
538                return;
539            }
540
541            RestoreObserver observer = new RestoreObserver();
542            int err = mRestore.restorePackage(pkg, observer);
543            if (err == 0) {
544                // Off and running -- wait for the restore to complete
545                observer.waitForCompletion();
546            } else {
547                System.err.println("Unable to restore package " + pkg);
548            }
549
550            // And finally shut down the session
551            mRestore.endRestoreSession();
552        } catch (RemoteException e) {
553            System.err.println(e.toString());
554            System.err.println(BMGR_NOT_RUNNING_ERR);
555        }
556    }
557
558    private void doRestoreAll(long token, HashSet<String> filter) {
559        RestoreObserver observer = new RestoreObserver();
560
561        try {
562            boolean didRestore = false;
563            mRestore = mBmgr.beginRestoreSession(null, null);
564            if (mRestore == null) {
565                System.err.println(BMGR_NOT_RUNNING_ERR);
566                return;
567            }
568            RestoreSet[] sets = null;
569            int err = mRestore.getAvailableRestoreSets(observer);
570            if (err == 0) {
571                observer.waitForCompletion();
572                sets = observer.sets;
573                if (sets != null) {
574                    for (RestoreSet s : sets) {
575                        if (s.token == token) {
576                            System.out.println("Scheduling restore: " + s.name);
577                            if (filter == null) {
578                                didRestore = (mRestore.restoreAll(token, observer) == 0);
579                            } else {
580                                String[] names = new String[filter.size()];
581                                filter.toArray(names);
582                                didRestore = (mRestore.restoreSome(token, observer, names) == 0);
583                            }
584                            break;
585                        }
586                    }
587                }
588            }
589            if (!didRestore) {
590                if (sets == null || sets.length == 0) {
591                    System.out.println("No available restore sets; no restore performed");
592                } else {
593                    System.out.println("No matching restore set token.  Available sets:");
594                    printRestoreSets(sets);
595                }
596            }
597
598            // if we kicked off a restore successfully, we have to wait for it
599            // to complete before we can shut down the restore session safely
600            if (didRestore) {
601                observer.waitForCompletion();
602            }
603
604            // once the restore has finished, close down the session and we're done
605            mRestore.endRestoreSession();
606        } catch (RemoteException e) {
607            System.err.println(e.toString());
608            System.err.println(BMGR_NOT_RUNNING_ERR);
609        }
610    }
611
612    private void doPrintWhitelist() {
613        try {
614            final String[] whitelist = mBmgr.getTransportWhitelist();
615            if (whitelist != null) {
616                for (String transport : whitelist) {
617                    System.out.println(transport);
618                }
619            }
620        } catch (RemoteException e) {
621            System.err.println(e.toString());
622            System.err.println(BMGR_NOT_RUNNING_ERR);
623        }
624    }
625
626    private String nextArg() {
627        if (mNextArg >= mArgs.length) {
628            return null;
629        }
630        String arg = mArgs[mNextArg];
631        mNextArg++;
632        return arg;
633    }
634
635    private static void showUsage() {
636        System.err.println("usage: bmgr [backup|restore|list|transport|run]");
637        System.err.println("       bmgr backup PACKAGE");
638        System.err.println("       bmgr enable BOOL");
639        System.err.println("       bmgr enabled");
640        System.err.println("       bmgr list transports");
641        System.err.println("       bmgr list sets");
642        System.err.println("       bmgr transport WHICH");
643        System.err.println("       bmgr restore TOKEN");
644        System.err.println("       bmgr restore TOKEN PACKAGE...");
645        System.err.println("       bmgr restore PACKAGE");
646        System.err.println("       bmgr run");
647        System.err.println("       bmgr wipe TRANSPORT PACKAGE");
648        System.err.println("       bmgr fullbackup PACKAGE...");
649        System.err.println("       bmgr backupnow --all|PACKAGE...");
650        System.err.println("");
651        System.err.println("The 'backup' command schedules a backup pass for the named package.");
652        System.err.println("Note that the backup pass will effectively be a no-op if the package");
653        System.err.println("does not actually have changed data to store.");
654        System.err.println("");
655        System.err.println("The 'enable' command enables or disables the entire backup mechanism.");
656        System.err.println("If the argument is 'true' it will be enabled, otherwise it will be");
657        System.err.println("disabled.  When disabled, neither backup or restore operations will");
658        System.err.println("be performed.");
659        System.err.println("");
660        System.err.println("The 'enabled' command reports the current enabled/disabled state of");
661        System.err.println("the backup mechanism.");
662        System.err.println("");
663        System.err.println("The 'list transports' command reports the names of the backup transports");
664        System.err.println("currently available on the device.  These names can be passed as arguments");
665        System.err.println("to the 'transport' and 'wipe' commands.  The currently active transport");
666        System.err.println("is indicated with a '*' character.");
667        System.err.println("");
668        System.err.println("The 'list sets' command reports the token and name of each restore set");
669        System.err.println("available to the device via the currently active transport.");
670        System.err.println("");
671        System.err.println("The 'transport' command designates the named transport as the currently");
672        System.err.println("active one.  This setting is persistent across reboots.");
673        System.err.println("");
674        System.err.println("The 'restore' command when given just a restore token initiates a full-system");
675        System.err.println("restore operation from the currently active transport.  It will deliver");
676        System.err.println("the restore set designated by the TOKEN argument to each application");
677        System.err.println("that had contributed data to that restore set.");
678        System.err.println("");
679        System.err.println("The 'restore' command when given a token and one or more package names");
680        System.err.println("initiates a restore operation of just those given packages from the restore");
681        System.err.println("set designated by the TOKEN argument.  It is effectively the same as the");
682        System.err.println("'restore' operation supplying only a token, but applies a filter to the");
683        System.err.println("set of applications to be restored.");
684        System.err.println("");
685        System.err.println("The 'restore' command when given just a package name intiates a restore of");
686        System.err.println("just that one package according to the restore set selection algorithm");
687        System.err.println("used by the RestoreSession.restorePackage() method.");
688        System.err.println("");
689        System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
690        System.err.println("immediately, without the usual waiting period for batching together");
691        System.err.println("data changes.");
692        System.err.println("");
693        System.err.println("The 'wipe' command causes all backed-up data for the given package to be");
694        System.err.println("erased from the given transport's storage.  The next backup operation");
695        System.err.println("that the given application performs will rewrite its entire data set.");
696        System.err.println("Transport names to use here are those reported by 'list transports'.");
697        System.err.println("");
698        System.err.println("The 'fullbackup' command induces a full-data stream backup for one or more");
699        System.err.println("packages.  The data is sent via the currently active transport.");
700        System.err.println("");
701        System.err.println("The 'backupnow' command runs an immediate backup for one or more packages.");
702        System.err.println("    --all flag runs backup for all eligible packages.");
703        System.err.println("For each package it will run key/value or full data backup ");
704        System.err.println("depending on the package's manifest declarations.");
705        System.err.println("The data is sent via the currently active transport.");
706    }
707}
708