• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.BackupManager;
20 import android.app.backup.BackupProgress;
21 import android.app.backup.RestoreSet;
22 import android.app.backup.IBackupManager;
23 import android.app.backup.IBackupObserver;
24 import android.app.backup.IRestoreObserver;
25 import android.app.backup.IRestoreSession;
26 import android.content.pm.IPackageManager;
27 import android.content.pm.PackageInfo;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.os.UserHandle;
31 
32 import java.util.ArrayList;
33 import java.util.HashSet;
34 import java.util.List;
35 
36 public 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 
main(String[] args)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 
run(String[] args)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 
enableToString(boolean enabled)134     private String enableToString(boolean enabled) {
135         return enabled ? "enabled" : "disabled";
136     }
137 
doEnabled()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 
doEnable()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 
doRun()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 
doBackup()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 
doFullTransportBackup()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
onUpdate(String currentPackage, BackupProgress backupProgress)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
onResult(String currentPackage, int status)222         public void onResult(String currentPackage, int status) {
223             System.out.println("Package " + currentPackage + " with result: "
224                     + convertBackupStatusToString(status));
225         }
226 
227         @Override
backupFinished(int status)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 
waitForCompletion()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 
convertBackupStatusToString(int errorCode)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 
backupNowAllPackages()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 
backupNowPackages(List<String> packages)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 
doBackupNow()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 
doTransport()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 
doWipe()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 
doList()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 
doListTransports()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 
doListRestoreSets()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 
printRestoreSets(RestoreSet[] sets)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 
restoreSetsAvailable(RestoreSet[] result)466         public void restoreSetsAvailable(RestoreSet[] result) {
467             synchronized (this) {
468                 sets = result;
469                 done = true;
470                 this.notify();
471             }
472         }
473 
restoreStarting(int numPackages)474         public void restoreStarting(int numPackages) {
475             System.out.println("restoreStarting: " + numPackages + " packages");
476         }
477 
onUpdate(int nowBeingRestored, String currentPackage)478         public void onUpdate(int nowBeingRestored, String currentPackage) {
479             System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage);
480         }
481 
restoreFinished(int error)482         public void restoreFinished(int error) {
483             System.out.println("restoreFinished: " + error);
484             synchronized (this) {
485                 done = true;
486                 this.notify();
487             }
488         }
489 
waitForCompletion()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 
doRestore()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 
doRestorePackage(String pkg)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 
doRestoreAll(long token, HashSet<String> filter)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 
doPrintWhitelist()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 
nextArg()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 
showUsage()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