FullBackupUtils.java revision 2c2c856b3a60e96e09261d2513b43acb7ff4b070
1package com.android.server.backup.utils; 2 3import android.content.pm.PackageInfo; 4import android.content.pm.PackageManager; 5import android.content.pm.Signature; 6import android.os.Build; 7import android.os.ParcelFileDescriptor; 8import android.util.StringBuilderPrinter; 9 10import com.android.server.backup.RefactoredBackupManagerService; 11 12import java.io.DataInputStream; 13import java.io.File; 14import java.io.FileInputStream; 15import java.io.FileOutputStream; 16import java.io.IOException; 17import java.io.OutputStream; 18 19/** 20 * Low-level utility methods for full backup. 21 */ 22public class FullBackupUtils { 23 /** 24 * Reads data from pipe and writes it to the stream in chunks of up to 32KB. 25 * 26 * @param inPipe - pipe to read the data from. 27 * @param out - stream to write the data to. 28 * @throws IOException - in case of an error. 29 */ 30 public static void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out) 31 throws IOException { 32 // We do not take close() responsibility for the pipe FD 33 FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor()); 34 DataInputStream in = new DataInputStream(raw); 35 36 byte[] buffer = new byte[32 * 1024]; 37 int chunkTotal; 38 while ((chunkTotal = in.readInt()) > 0) { 39 while (chunkTotal > 0) { 40 int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal; 41 int nRead = in.read(buffer, 0, toRead); 42 out.write(buffer, 0, nRead); 43 chunkTotal -= nRead; 44 } 45 } 46 } 47 48 /** 49 * Writes app manifest to the given manifest file. 50 * 51 * @param pkg - app package, which manifest to write. 52 * @param packageManager - {@link PackageManager} instance. 53 * @param manifestFile - target manifest file. 54 * @param withApk - whether include apk or not. 55 * @param withWidgets - whether to write widgets data. 56 * @throws IOException - in case of an error. 57 */ 58 // TODO: withWidgets is not used, decide whether it is needed. 59 public static void writeAppManifest(PackageInfo pkg, PackageManager packageManager, 60 File manifestFile, boolean withApk, boolean withWidgets) throws IOException { 61 // Manifest format. All data are strings ending in LF: 62 // BACKUP_MANIFEST_VERSION, currently 1 63 // 64 // Version 1: 65 // package name 66 // package's versionCode 67 // platform versionCode 68 // getInstallerPackageName() for this package (maybe empty) 69 // boolean: "1" if archive includes .apk; any other string means not 70 // number of signatures == N 71 // N*: signature byte array in ascii format per Signature.toCharsString() 72 StringBuilder builder = new StringBuilder(4096); 73 StringBuilderPrinter printer = new StringBuilderPrinter(builder); 74 75 printer.println(Integer.toString(RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION)); 76 printer.println(pkg.packageName); 77 printer.println(Integer.toString(pkg.versionCode)); 78 printer.println(Integer.toString(Build.VERSION.SDK_INT)); 79 80 String installerName = packageManager.getInstallerPackageName(pkg.packageName); 81 printer.println((installerName != null) ? installerName : ""); 82 83 printer.println(withApk ? "1" : "0"); 84 if (pkg.signatures == null) { 85 printer.println("0"); 86 } else { 87 printer.println(Integer.toString(pkg.signatures.length)); 88 for (Signature sig : pkg.signatures) { 89 printer.println(sig.toCharsString()); 90 } 91 } 92 93 FileOutputStream outstream = new FileOutputStream(manifestFile); 94 outstream.write(builder.toString().getBytes()); 95 outstream.close(); 96 97 // We want the manifest block in the archive stream to be idempotent: 98 // each time we generate a backup stream for the app, we want the manifest 99 // block to be identical. The underlying tar mechanism sees it as a file, 100 // though, and will propagate its mtime, causing the tar header to vary. 101 // Avoid this problem by pinning the mtime to zero. 102 manifestFile.setLastModified(0); 103 } 104} 105