Bmgr.java revision 04686f428995fde3f6f5f5f12ccdd135f885ac84
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 38 public static void main(String[] args) { 39 try { 40 new Bmgr().run(args); 41 } catch (Exception e) { 42 System.err.println("Exception caught:"); 43 e.printStackTrace(); 44 } 45 } 46 47 public void run(String[] args) { 48 boolean validCommand = false; 49 if (args.length < 1) { 50 showUsage(); 51 return; 52 } 53 54 mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService("backup")); 55 if (mBmgr == null) { 56 System.err.println(BMGR_NOT_RUNNING_ERR); 57 return; 58 } 59 60 mArgs = args; 61 String op = args[0]; 62 mNextArg = 1; 63 64 if ("enabled".equals(op)) { 65 doEnabled(); 66 return; 67 } 68 69 if ("enable".equals(op)) { 70 doEnable(); 71 return; 72 } 73 74 if ("run".equals(op)) { 75 doRun(); 76 return; 77 } 78 79 if ("backup".equals(op)) { 80 doBackup(); 81 return; 82 } 83 84 if ("list".equals(op)) { 85 doList(); 86 return; 87 } 88 89 if ("restore".equals(op)) { 90 doRestore(); 91 return; 92 } 93 94 if ("transport".equals(op)) { 95 doTransport(); 96 return; 97 } 98 99 if ("wipe".equals(op)) { 100 doWipe(); 101 return; 102 } 103 104 System.err.println("Unknown command"); 105 showUsage(); 106 } 107 108 private String enableToString(boolean enabled) { 109 return enabled ? "enabled" : "disabled"; 110 } 111 112 private void doEnabled() { 113 try { 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); 120 } 121 } 122 123 private void doEnable() { 124 String arg = nextArg(); 125 if (arg == null) { 126 showUsage(); 127 return; 128 } 129 130 try { 131 boolean enable = Boolean.parseBoolean(arg); 132 mBmgr.setBackupEnabled(enable); 133 System.out.println("Backup Manager now " + enableToString(enable)); 134 } catch (NumberFormatException e) { 135 showUsage(); 136 return; 137 } catch (RemoteException e) { 138 System.err.println(e.toString()); 139 System.err.println(BMGR_NOT_RUNNING_ERR); 140 } 141 } 142 143 private void doRun() { 144 try { 145 mBmgr.backupNow(); 146 } catch (RemoteException e) { 147 System.err.println(e.toString()); 148 System.err.println(BMGR_NOT_RUNNING_ERR); 149 } 150 } 151 152 private void doBackup() { 153 boolean isFull = false; 154 String pkg = nextArg(); 155 if ("-f".equals(pkg)) { 156 isFull = true; 157 pkg = nextArg(); 158 } 159 160 if (pkg == null || pkg.startsWith("-")) { 161 showUsage(); 162 return; 163 } 164 165 try { 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); 171 } 172 } 173 174 private void doTransport() { 175 try { 176 String which = nextArg(); 177 if (which == null) { 178 showUsage(); 179 return; 180 } 181 182 String old = mBmgr.selectBackupTransport(which); 183 if (old == null) { 184 System.out.println("Unknown transport '" + which 185 + "' specified; no changes made."); 186 } else { 187 System.out.println("Selected transport " + which + " (formerly " + old + ")"); 188 } 189 } catch (RemoteException e) { 190 System.err.println(e.toString()); 191 System.err.println(BMGR_NOT_RUNNING_ERR); 192 } 193 } 194 195 private void doWipe() { 196 String pkg = nextArg(); 197 if (pkg == null) { 198 showUsage(); 199 return; 200 } 201 202 try { 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); 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 String curTransport = mBmgr.getCurrentTransport(); 221 mRestore = mBmgr.beginRestoreSession(curTransport); 222 if (mRestore == null) { 223 System.err.println(BMGR_NOT_RUNNING_ERR); 224 return; 225 } 226 227 if ("sets".equals(arg)) { 228 doListRestoreSets(); 229 } else if ("transports".equals(arg)) { 230 doListTransports(); 231 } 232 233 mRestore.endRestoreSession(); 234 } catch (RemoteException e) { 235 System.err.println(e.toString()); 236 System.err.println(BMGR_NOT_RUNNING_ERR); 237 } 238 } 239 240 private void doListTransports() { 241 try { 242 String current = mBmgr.getCurrentTransport(); 243 String[] transports = mBmgr.listAllTransports(); 244 if (transports == null || transports.length == 0) { 245 System.out.println("No transports available."); 246 return; 247 } 248 249 for (String t : transports) { 250 String pad = (t.equals(current)) ? " * " : " "; 251 System.out.println(pad + t); 252 } 253 } catch (RemoteException e) { 254 System.err.println(e.toString()); 255 System.err.println(BMGR_NOT_RUNNING_ERR); 256 } 257 } 258 259 private void doListRestoreSets() { 260 try { 261 RestoreObserver observer = new RestoreObserver(); 262 int err = mRestore.getAvailableRestoreSets(observer); 263 if (err != 0) { 264 System.out.println("Unable to request restore sets"); 265 } else { 266 observer.waitForCompletion(); 267 printRestoreSets(observer.sets); 268 } 269 } catch (RemoteException e) { 270 System.err.println(e.toString()); 271 System.err.println(TRANSPORT_NOT_RUNNING_ERR); 272 } 273 } 274 275 private void printRestoreSets(RestoreSet[] sets) { 276 if (sets == null || sets.length == 0) { 277 System.out.println("No restore sets"); 278 return; 279 } 280 for (RestoreSet s : sets) { 281 System.out.println(" " + Long.toHexString(s.token) + " : " + s.name); 282 } 283 } 284 285 class RestoreObserver extends IRestoreObserver.Stub { 286 boolean done; 287 RestoreSet[] sets = null; 288 289 public void restoreSetsAvailable(RestoreSet[] result) { 290 synchronized (this) { 291 sets = result; 292 done = true; 293 this.notify(); 294 } 295 } 296 297 public void restoreStarting(int numPackages) { 298 System.out.println("restoreStarting: " + numPackages + " packages"); 299 } 300 301 public void onUpdate(int nowBeingRestored, String currentPackage) { 302 System.out.println("onUpdate: " + nowBeingRestored + " = " + currentPackage); 303 } 304 305 public void restoreFinished(int error) { 306 System.out.println("restoreFinished: " + error); 307 synchronized (this) { 308 done = true; 309 this.notify(); 310 } 311 } 312 313 public void waitForCompletion() { 314 // The restoreFinished() callback will throw the 'done' flag; we 315 // just sit and wait on that notification. 316 synchronized (this) { 317 while (!this.done) { 318 try { 319 this.wait(); 320 } catch (InterruptedException ex) { 321 } 322 } 323 } 324 } 325 } 326 327 private void doRestore() { 328 String arg = nextArg(); 329 if (arg == null) { 330 showUsage(); 331 return; 332 } 333 334 if (arg.indexOf('.') >= 0) { 335 // it's a package name 336 doRestorePackage(arg); 337 } else { 338 try { 339 long token = Long.parseLong(arg, 16); 340 doRestoreAll(token); 341 } catch (NumberFormatException e) { 342 showUsage(); 343 return; 344 } 345 } 346 347 System.out.println("done"); 348 } 349 350 private void doRestorePackage(String pkg) { 351 try { 352 String curTransport = mBmgr.getCurrentTransport(); 353 mRestore = mBmgr.beginRestoreSession(curTransport); 354 if (mRestore == null) { 355 System.err.println(BMGR_NOT_RUNNING_ERR); 356 return; 357 } 358 359 RestoreObserver observer = new RestoreObserver(); 360 int err = mRestore.restorePackage(pkg, observer); 361 if (err == 0) { 362 // Off and running -- wait for the restore to complete 363 observer.waitForCompletion(); 364 } else { 365 System.err.println("Unable to restore package " + pkg); 366 } 367 368 // And finally shut down the session 369 mRestore.endRestoreSession(); 370 } catch (RemoteException e) { 371 System.err.println(e.toString()); 372 System.err.println(BMGR_NOT_RUNNING_ERR); 373 } 374 } 375 376 private void doRestoreAll(long token) { 377 RestoreObserver observer = new RestoreObserver(); 378 379 try { 380 boolean didRestore = false; 381 String curTransport = mBmgr.getCurrentTransport(); 382 mRestore = mBmgr.beginRestoreSession(curTransport); 383 if (mRestore == null) { 384 System.err.println(BMGR_NOT_RUNNING_ERR); 385 return; 386 } 387 RestoreSet[] sets = null; 388 int err = mRestore.getAvailableRestoreSets(observer); 389 if (err == 0) { 390 observer.waitForCompletion(); 391 sets = observer.sets; 392 for (RestoreSet s : sets) { 393 if (s.token == token) { 394 System.out.println("Scheduling restore: " + s.name); 395 didRestore = (mRestore.restoreAll(token, observer) == 0); 396 break; 397 } 398 } 399 } 400 if (!didRestore) { 401 if (sets == null || sets.length == 0) { 402 System.out.println("No available restore sets; no restore performed"); 403 } else { 404 System.out.println("No matching restore set token. Available sets:"); 405 printRestoreSets(sets); 406 } 407 } 408 409 // if we kicked off a restore successfully, we have to wait for it 410 // to complete before we can shut down the restore session safely 411 if (didRestore) { 412 observer.waitForCompletion(); 413 } 414 415 // once the restore has finished, close down the session and we're done 416 mRestore.endRestoreSession(); 417 } catch (RemoteException e) { 418 System.err.println(e.toString()); 419 System.err.println(BMGR_NOT_RUNNING_ERR); 420 } 421 } 422 423 private String nextArg() { 424 if (mNextArg >= mArgs.length) { 425 return null; 426 } 427 String arg = mArgs[mNextArg]; 428 mNextArg++; 429 return arg; 430 } 431 432 private static void showUsage() { 433 System.err.println("usage: bmgr [backup|restore|list|transport|run]"); 434 System.err.println(" bmgr backup PACKAGE"); 435 System.err.println(" bmgr enable BOOL"); 436 System.err.println(" bmgr enabled"); 437 System.err.println(" bmgr list transports"); 438 System.err.println(" bmgr list sets"); 439 System.err.println(" bmgr transport WHICH"); 440 System.err.println(" bmgr restore TOKEN"); 441 System.err.println(" bmgr restore PACKAGE"); 442 System.err.println(" bmgr run"); 443 System.err.println(" bmgr wipe PACKAGE"); 444 System.err.println(""); 445 System.err.println("The 'backup' command schedules a backup pass for the named package."); 446 System.err.println("Note that the backup pass will effectively be a no-op if the package"); 447 System.err.println("does not actually have changed data to store."); 448 System.err.println(""); 449 System.err.println("The 'enable' command enables or disables the entire backup mechanism."); 450 System.err.println("If the argument is 'true' it will be enabled, otherwise it will be"); 451 System.err.println("disabled. When disabled, neither backup or restore operations will"); 452 System.err.println("be performed."); 453 System.err.println(""); 454 System.err.println("The 'enabled' command reports the current enabled/disabled state of"); 455 System.err.println("the backup mechanism."); 456 System.err.println(""); 457 System.err.println("The 'list transports' command reports the names of the backup transports"); 458 System.err.println("currently available on the device. These names can be passed as arguments"); 459 System.err.println("to the 'transport' command. The currently selected transport is indicated"); 460 System.err.println("with a '*' character."); 461 System.err.println(""); 462 System.err.println("The 'list sets' command reports the token and name of each restore set"); 463 System.err.println("available to the device via the current transport."); 464 System.err.println(""); 465 System.err.println("The 'transport' command designates the named transport as the currently"); 466 System.err.println("active one. This setting is persistent across reboots."); 467 System.err.println(""); 468 System.err.println("The 'restore' command when given a restore token initiates a full-system"); 469 System.err.println("restore operation from the currently active transport. It will deliver"); 470 System.err.println("the restore set designated by the TOKEN argument to each application"); 471 System.err.println("that had contributed data to that restore set."); 472 System.err.println(""); 473 System.err.println("The 'restore' command when given a package name intiates a restore of"); 474 System.err.println("just that one package according to the restore set selection algorithm"); 475 System.err.println("used by the RestoreSession.restorePackage() method."); 476 System.err.println(""); 477 System.err.println("The 'run' command causes any scheduled backup operation to be initiated"); 478 System.err.println("immediately, without the usual waiting period for batching together"); 479 System.err.println("data changes."); 480 System.err.println(""); 481 System.err.println("The 'wipe' command causes all backed-up data for the given package to be"); 482 System.err.println("erased from the current transport's storage. The next backup operation"); 483 System.err.println("that the given application performs will rewrite its entire data set."); 484 } 485} 486