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