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