////////////////////////github///////////////////////////////////////
// Write the global file header. All strings are UTF-8 encoded; lines end
// with a '\n' byte. Actual backup data begins immediately following the
// final '\n'.
//
// line 1: "ANDROID BACKUP"
// line 2: backup file format version, currently "2"
// line 3: compressed? "0" if not compressed, "1" if compressed.
// line 4: name of encryption algorithm [currently only "none" or "AES-256"]
//
// When line 4 is not "none", then additional header data follows:
//
/ line 5: user password salt [hex]
// line 6: master key checksum salt [hex]
// line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
// line 8: IV of the user key [hex]
// line 9: master key blob [hex]
// IV of the master key, master key itself, master key checksum hash
//
// The master key checksum is the master key plus its checksum salt, run through
// 10k rounds of PBKDF2. This is used to verify that the user has supplied the
// correct password for decrypting the archive: the master key decrypted from
// the archive using the user-supplied password is also run through PBKDF2 in
// this way, and if the result does not match the checksum as stored in the
// archive, then we know that the user-supplied password does not match the
// archive's.
static final int BACKUP_FILE_VERSION = 3;
static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
static final int BACKUP_PW_FILE_VERSION = 2;
static final String BACKUP_METADATA_FILENAME = "_meta";
StringBuilder headerbuf = new StringBuilder(1024);
headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
////////////////////////////abe//////////////////////////////////
StringBuilder headerbuf = new StringBuilder(1024);
headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
// integer, no trailing \n
headerbuf.append(isKitKat ? BACKUP_FILE_V2 : BACKUP_FILE_V1);
headerbuf.append(compressing ? "\n1\n" : "\n0\n");
try {
// Set up the encryption stage if appropriate, and emit the correct header
if (encrypting) {
finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
} else {
headerbuf.append("none\n");
}
// Shared storage if requested
if (mIncludeShared) {
try {
pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
backupQueue.add(pkg);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Unable to find shared-storage backup handler");
}
}
// Now actually run the constructed backup sequence
int N = backupQueue.size();
for (int i = 0; i < N; i++) {
pkg = backupQueue.get(i);
final boolean isSharedStorage =
pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
mBackupEngine = new FullBackupEngine(out, pkg.packageName, null, mIncludeApks);
sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
mBackupEngine.backupOnePackage(pkg);
// after the app's agent runs to handle its private filesystem
// contents, back up any OBB content it has on its behalf.
if (mIncludeObbs) {
boolean obbOkay = obbConnection.backupObbs(pkg, out);
if (!obbOkay) {
throw new RuntimeException("Failure writing OBB stack for " + pkg);
}
}
}
// Done!
finalizeBackup(out);
.....
try {
if (out != null) out.close();
mOutputFile.close();
} catch (IOException e) {
/* nothing we can do about this */
}
synchronized (mCurrentOpLock) {
mCurrentOperations.clear();
}
synchronized (mLatch) {
mLatch.set(true);
mLatch.notifyAll();
}
sendEndBackup();
obbConnection.tearDown();
if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
mWakelock.release();
public void run() {
try {
FullBackupDataOutput output = new FullBackupDataOutput(mPipe);
if (mWriteManifest) {
final boolean writeWidgetData = mWidgetData != null;
if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
writeAppManifest(mPackage, mManifestFile, mSendApk, writeWidgetData);
FullBackup.backupToTar(mPackage.packageName, null, null,
mFilesDir.getAbsolutePath(),
mManifestFile.getAbsolutePath(),
output);
mManifestFile.delete();
// We only need to write a metadata file if we have widget data to stash
if (writeWidgetData) {
writeMetadata(mPackage, mMetadataFile, mWidgetData);
FullBackup.backupToTar(mPackage.packageName, null, null,
mFilesDir.getAbsolutePath(),
mMetadataFile.getAbsolutePath(),
output);
mMetadataFile.delete();
}
}
if (mSendApk) {
writeApkToBackup(mPackage, output);
}
if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, null);
mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
} catch (IOException e) {
Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
} catch (RemoteException e) {
Slog.e(TAG, "Remote agent vanished during full backup of "
+ mPackage.packageName);
} finally {
try {
mPipe.close();
} catch (IOException e) {}
}
}
private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
// Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
// TODO: handle backing up split APKs
final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
final String apkDir = new File(appSourceDir).getParent();
FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
apkDir, appSourceDir, output);
// TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
// doesn't have access to external storage.
// Save associated .obb content if it exists and we did save the apk
// check for .obb and save those too
final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
if (obbDir != null) {
if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
File[] obbFiles = obbDir.listFiles();
if (obbFiles != null) {
final String obbDirName = obbDir.getAbsolutePath();
for (File obb : obbFiles) {
FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
obbDirName, obb.getAbsolutePath(), output);
}
}
}
}
private void writeAppManifest(PackageInfo pkg, File manifestFile,
boolean withApk, boolean withWidgets) throws IOException {
// Manifest format. All data are strings ending in LF:
// BACKUP_MANIFEST_VERSION, currently 1
//
// Version 1:
// package name
// package's versionCode
// platform versionCode
// getInstallerPackageName() for this package (maybe empty)
// boolean: "1" if archive includes .apk; any other string means not
// number of signatures == N
// N*: signature byte array in ascii format per Signature.toCharsString()
StringBuilder builder = new StringBuilder(4096);
StringBuilderPrinter printer = new StringBuilderPrinter(builder);
printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
printer.println(pkg.packageName);
printer.println(Integer.toString(pkg.versionCode));
printer.println(Integer.toString(Build.VERSION.SDK_INT));
String installerName = mPackageManager.getInstallerPackageName(pkg.packageName);
printer.println((installerName != null) ? installerName : "");
printer.println(withApk ? "1" : "0");
if (pkg.signatures == null) {
printer.println("0");
} else {
printer.println(Integer.toString(pkg.signatures.length));
for (Signature sig : pkg.signatures) {
printer.println(sig.toCharsString());
}
}
FileOutputStream outstream = new FileOutputStream(manifestFile);
outstream.write(builder.toString().getBytes());
outstream.close();
// We want the manifest block in the archive stream to be idempotent:
// each time we generate a backup stream for the app, we want the manifest
// block to be identical. The underlying tar mechanism sees it as a file,
// though, and will propagate its mtime, causing the tar header to vary.
// Avoid this problem by pinning the mtime to zero.
manifestFile.setLastModified(0);
}