2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.commands.bmgr;
19 import android.app.backup.RestoreSet;
20 import android.app.backup.IBackupManager;
21 import android.app.backup.IRestoreObserver;
22 import android.app.backup.IRestoreSession;
23 import android.os.RemoteException;
24 import android.os.ServiceManager;
26 public final class Bmgr {
28 IRestoreSession mRestore;
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?";
35 private String[] mArgs;
38 public static void main(String[] args) {
41 } catch (Exception e) {
42 System.err.println("Exception caught:");
47 public void run(String[] args) {
48 boolean validCommand = false;
49 if (args.length < 1) {
54 mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
56 System.err.println(BMGR_NOT_RUNNING_ERR);
64 if ("enabled".equals(op)) {
69 if ("enable".equals(op)) {
74 if ("run".equals(op)) {
79 if ("backup".equals(op)) {
84 if ("list".equals(op)) {
89 if ("restore".equals(op)) {
94 if ("transport".equals(op)) {
99 if ("wipe".equals(op)) {
104 System.err.println("Unknown command");
108 private String enableToString(boolean enabled) {
109 return enabled ? "enabled" : "disabled";
112 private void doEnabled() {
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);
123 private void doEnable() {
124 String arg = nextArg();
131 boolean enable = Boolean.parseBoolean(arg);
132 mBmgr.setBackupEnabled(enable);
133 System.out.println("Backup Manager now " + enableToString(enable));
134 } catch (NumberFormatException e) {
137 } catch (RemoteException e) {
138 System.err.println(e.toString());
139 System.err.println(BMGR_NOT_RUNNING_ERR);
143 private void doRun() {
146 } catch (RemoteException e) {
147 System.err.println(e.toString());
148 System.err.println(BMGR_NOT_RUNNING_ERR);
152 private void doBackup() {
153 boolean isFull = false;
154 String pkg = nextArg();
155 if ("-f".equals(pkg)) {
160 if (pkg == null || pkg.startsWith("-")) {
166 // !!! TODO: handle full backup
167 mBmgr.dataChanged(pkg);
168 } catch (RemoteException e) {
169 System.err.println(e.toString());
170 System.err.println(BMGR_NOT_RUNNING_ERR);
174 private void doTransport() {
176 String which = nextArg();
182 String old = mBmgr.selectBackupTransport(which);
184 System.out.println("Unknown transport '" + which
185 + "' specified; no changes made.");
187 System.out.println("Selected transport " + which + " (formerly " + old + ")");
189 } catch (RemoteException e) {
190 System.err.println(e.toString());
191 System.err.println(BMGR_NOT_RUNNING_ERR);
195 private void doWipe() {
196 String pkg = nextArg();
203 mBmgr.clearBackupData(pkg);
204 System.out.println("Wiped backup data for " + pkg);
205 } catch (RemoteException e) {
206 System.err.println(e.toString());
207 System.err.println(BMGR_NOT_RUNNING_ERR);
211 private void doList() {
212 String arg = nextArg(); // sets, transports, packages set#
213 if ("transports".equals(arg)) {
218 // The rest of the 'list' options work with a restore session on the current transport
220 mRestore = mBmgr.beginRestoreSession(null, null);
221 if (mRestore == null) {
222 System.err.println(BMGR_NOT_RUNNING_ERR);
226 if ("sets".equals(arg)) {
228 } else if ("transports".equals(arg)) {
232 mRestore.endRestoreSession();
233 } catch (RemoteException e) {
234 System.err.println(e.toString());
235 System.err.println(BMGR_NOT_RUNNING_ERR);
239 private void doListTransports() {
241 String current = mBmgr.getCurrentTransport();
242 String[] transports = mBmgr.listAllTransports();
243 if (transports == null || transports.length == 0) {
244 System.out.println("No transports available.");
248 for (String t : transports) {
249 String pad = (t.equals(current)) ? " * " : " ";
250 System.out.println(pad + t);
252 } catch (RemoteException e) {
253 System.err.println(e.toString());
254 System.err.println(BMGR_NOT_RUNNING_ERR);
258 private void doListRestoreSets() {
260 RestoreObserver observer = new RestoreObserver();
261 int err = mRestore.getAvailableRestoreSets(observer);
263 System.out.println("Unable to request restore sets");
265 observer.waitForCompletion();
266 printRestoreSets(observer.sets);
268 } catch (RemoteException e) {
269 System.err.println(e.toString());
270 System.err.println(TRANSPORT_NOT_RUNNING_ERR);
274 private void printRestoreSets(RestoreSet[] sets) {
275 if (sets == null || sets.length == 0) {
276 System.out.println("No restore sets");
279 for (RestoreSet s : sets) {
280 System.out.println(" " + Long.toHexString(s.token) + " : " + s.name);
284 class RestoreObserver extends IRestoreObserver.Stub {
286 RestoreSet[] sets = null;
288 public void restoreSetsAvailable(RestoreSet[] result) {
289 synchronized (this) {
296 public void restoreStarting(int numPackages) {
297 System.out.println("restoreStarting: " + numPackages + " packages");
300 public void onUpdate(int nowBeingRestored, String currentPackage) {
301 System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage);
304 public void restoreFinished(int error) {
305 System.out.println("restoreFinished: " + error);
306 synchronized (this) {
312 public void waitForCompletion() {
313 // The restoreFinished() callback will throw the 'done' flag; we
314 // just sit and wait on that notification.
315 synchronized (this) {
319 } catch (InterruptedException ex) {
326 private void doRestore() {
327 String arg = nextArg();
333 if (arg.indexOf('.') >= 0) {
334 // it's a package name
335 doRestorePackage(arg);
338 long token = Long.parseLong(arg, 16);
340 } catch (NumberFormatException e) {
346 System.out.println("done");
349 private void doRestorePackage(String pkg) {
351 mRestore = mBmgr.beginRestoreSession(pkg, null);
352 if (mRestore == null) {
353 System.err.println(BMGR_NOT_RUNNING_ERR);
357 RestoreObserver observer = new RestoreObserver();
358 int err = mRestore.restorePackage(pkg, observer);
360 // Off and running -- wait for the restore to complete
361 observer.waitForCompletion();
363 System.err.println("Unable to restore package " + pkg);
366 // And finally shut down the session
367 mRestore.endRestoreSession();
368 } catch (RemoteException e) {
369 System.err.println(e.toString());
370 System.err.println(BMGR_NOT_RUNNING_ERR);
374 private void doRestoreAll(long token) {
375 RestoreObserver observer = new RestoreObserver();
378 boolean didRestore = false;
379 mRestore = mBmgr.beginRestoreSession(null, null);
380 if (mRestore == null) {
381 System.err.println(BMGR_NOT_RUNNING_ERR);
384 RestoreSet[] sets = null;
385 int err = mRestore.getAvailableRestoreSets(observer);
387 observer.waitForCompletion();
388 sets = observer.sets;
389 for (RestoreSet s : sets) {
390 if (s.token == token) {
391 System.out.println("Scheduling restore: " + s.name);
392 didRestore = (mRestore.restoreAll(token, observer) == 0);
398 if (sets == null || sets.length == 0) {
399 System.out.println("No available restore sets; no restore performed");
401 System.out.println("No matching restore set token. Available sets:");
402 printRestoreSets(sets);
406 // if we kicked off a restore successfully, we have to wait for it
407 // to complete before we can shut down the restore session safely
409 observer.waitForCompletion();
412 // once the restore has finished, close down the session and we're done
413 mRestore.endRestoreSession();
414 } catch (RemoteException e) {
415 System.err.println(e.toString());
416 System.err.println(BMGR_NOT_RUNNING_ERR);
420 private String nextArg() {
421 if (mNextArg >= mArgs.length) {
424 String arg = mArgs[mNextArg];
429 private static void showUsage() {
430 System.err.println("usage: bmgr [backup|restore|list|transport|run]");
431 System.err.println(" bmgr backup PACKAGE");
432 System.err.println(" bmgr enable BOOL");
433 System.err.println(" bmgr enabled");
434 System.err.println(" bmgr list transports");
435 System.err.println(" bmgr list sets");
436 System.err.println(" bmgr transport WHICH");
437 System.err.println(" bmgr restore TOKEN");
438 System.err.println(" bmgr restore PACKAGE");
439 System.err.println(" bmgr run");
440 System.err.println(" bmgr wipe PACKAGE");
441 System.err.println("");
442 System.err.println("The 'backup' command schedules a backup pass for the named package.");
443 System.err.println("Note that the backup pass will effectively be a no-op if the package");
444 System.err.println("does not actually have changed data to store.");
445 System.err.println("");
446 System.err.println("The 'enable' command enables or disables the entire backup mechanism.");
447 System.err.println("If the argument is 'true' it will be enabled, otherwise it will be");
448 System.err.println("disabled. When disabled, neither backup or restore operations will");
449 System.err.println("be performed.");
450 System.err.println("");
451 System.err.println("The 'enabled' command reports the current enabled/disabled state of");
452 System.err.println("the backup mechanism.");
453 System.err.println("");
454 System.err.println("The 'list transports' command reports the names of the backup transports");
455 System.err.println("currently available on the device. These names can be passed as arguments");
456 System.err.println("to the 'transport' command. The currently selected transport is indicated");
457 System.err.println("with a '*' character.");
458 System.err.println("");
459 System.err.println("The 'list sets' command reports the token and name of each restore set");
460 System.err.println("available to the device via the current transport.");
461 System.err.println("");
462 System.err.println("The 'transport' command designates the named transport as the currently");
463 System.err.println("active one. This setting is persistent across reboots.");
464 System.err.println("");
465 System.err.println("The 'restore' command when given a restore token initiates a full-system");
466 System.err.println("restore operation from the currently active transport. It will deliver");
467 System.err.println("the restore set designated by the TOKEN argument to each application");
468 System.err.println("that had contributed data to that restore set.");
469 System.err.println("");
470 System.err.println("The 'restore' command when given a package name intiates a restore of");
471 System.err.println("just that one package according to the restore set selection algorithm");
472 System.err.println("used by the RestoreSession.restorePackage() method.");
473 System.err.println("");
474 System.err.println("The 'run' command causes any scheduled backup operation to be initiated");
475 System.err.println("immediately, without the usual waiting period for batching together");
476 System.err.println("data changes.");
477 System.err.println("");
478 System.err.println("The 'wipe' command causes all backed-up data for the given package to be");
479 System.err.println("erased from the current transport's storage. The next backup operation");
480 System.err.println("that the given application performs will rewrite its entire data set.");