1 /* 2 * Copyright (C) 2011 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 17 package android.app.backup; 18 19 import android.os.ParcelFileDescriptor; 20 import android.system.ErrnoException; 21 import android.system.Os; 22 import android.util.Log; 23 24 import java.io.File; 25 import java.io.FileInputStream; 26 import java.io.FileOutputStream; 27 import java.io.IOException; 28 29 /** 30 * Global constant definitions et cetera related to the full-backup-to-fd 31 * binary format. Nothing in this namespace is part of any API; it's all 32 * hidden details of the current implementation gathered into one location. 33 * 34 * @hide 35 */ 36 public class FullBackup { 37 static final String TAG = "FullBackup"; 38 39 public static final String APK_TREE_TOKEN = "a"; 40 public static final String OBB_TREE_TOKEN = "obb"; 41 public static final String ROOT_TREE_TOKEN = "r"; 42 public static final String DATA_TREE_TOKEN = "f"; 43 public static final String NO_BACKUP_TREE_TOKEN = "nb"; 44 public static final String DATABASE_TREE_TOKEN = "db"; 45 public static final String SHAREDPREFS_TREE_TOKEN = "sp"; 46 public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef"; 47 public static final String CACHE_TREE_TOKEN = "c"; 48 public static final String SHARED_STORAGE_TOKEN = "shared"; 49 50 public static final String APPS_PREFIX = "apps/"; 51 public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/"; 52 53 public static final String FULL_BACKUP_INTENT_ACTION = "fullback"; 54 public static final String FULL_RESTORE_INTENT_ACTION = "fullrest"; 55 public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken"; 56 57 /** 58 * @hide 59 */ backupToTar(String packageName, String domain, String linkdomain, String rootpath, String path, BackupDataOutput output)60 static public native int backupToTar(String packageName, String domain, 61 String linkdomain, String rootpath, String path, BackupDataOutput output); 62 63 /** 64 * Copy data from a socket to the given File location on permanent storage. The 65 * modification time and access mode of the resulting file will be set if desired, 66 * although group/all rwx modes will be stripped: the restored file will not be 67 * accessible from outside the target application even if the original file was. 68 * If the {@code type} parameter indicates that the result should be a directory, 69 * the socket parameter may be {@code null}; even if it is valid, no data will be 70 * read from it in this case. 71 * <p> 72 * If the {@code mode} argument is negative, then the resulting output file will not 73 * have its access mode or last modification time reset as part of this operation. 74 * 75 * @param data Socket supplying the data to be copied to the output file. If the 76 * output is a directory, this may be {@code null}. 77 * @param size Number of bytes of data to copy from the socket to the file. At least 78 * this much data must be available through the {@code data} parameter. 79 * @param type Must be either {@link BackupAgent#TYPE_FILE} for ordinary file data 80 * or {@link BackupAgent#TYPE_DIRECTORY} for a directory. 81 * @param mode Unix-style file mode (as used by the chmod(2) syscall) to be set on 82 * the output file or directory. group/all rwx modes are stripped even if set 83 * in this parameter. If this parameter is negative then neither 84 * the mode nor the mtime values will be applied to the restored file. 85 * @param mtime A timestamp in the standard Unix epoch that will be imposed as the 86 * last modification time of the output file. if the {@code mode} parameter is 87 * negative then this parameter will be ignored. 88 * @param outFile Location within the filesystem to place the data. This must point 89 * to a location that is writeable by the caller, preferably using an absolute path. 90 * @throws IOException 91 */ restoreFile(ParcelFileDescriptor data, long size, int type, long mode, long mtime, File outFile)92 static public void restoreFile(ParcelFileDescriptor data, 93 long size, int type, long mode, long mtime, File outFile) throws IOException { 94 if (type == BackupAgent.TYPE_DIRECTORY) { 95 // Canonically a directory has no associated content, so we don't need to read 96 // anything from the pipe in this case. Just create the directory here and 97 // drop down to the final metadata adjustment. 98 if (outFile != null) outFile.mkdirs(); 99 } else { 100 FileOutputStream out = null; 101 102 // Pull the data from the pipe, copying it to the output file, until we're done 103 try { 104 if (outFile != null) { 105 File parent = outFile.getParentFile(); 106 if (!parent.exists()) { 107 // in practice this will only be for the default semantic directories, 108 // and using the default mode for those is appropriate. 109 parent.mkdirs(); 110 } 111 out = new FileOutputStream(outFile); 112 } 113 } catch (IOException e) { 114 Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e); 115 } 116 117 byte[] buffer = new byte[32 * 1024]; 118 final long origSize = size; 119 FileInputStream in = new FileInputStream(data.getFileDescriptor()); 120 while (size > 0) { 121 int toRead = (size > buffer.length) ? buffer.length : (int)size; 122 int got = in.read(buffer, 0, toRead); 123 if (got <= 0) { 124 Log.w(TAG, "Incomplete read: expected " + size + " but got " 125 + (origSize - size)); 126 break; 127 } 128 if (out != null) { 129 try { 130 out.write(buffer, 0, got); 131 } catch (IOException e) { 132 // Problem writing to the file. Quit copying data and delete 133 // the file, but of course keep consuming the input stream. 134 Log.e(TAG, "Unable to write to file " + outFile.getPath(), e); 135 out.close(); 136 out = null; 137 outFile.delete(); 138 } 139 } 140 size -= got; 141 } 142 if (out != null) out.close(); 143 } 144 145 // Now twiddle the state to match the backup, assuming all went well 146 if (mode >= 0 && outFile != null) { 147 try { 148 // explicitly prevent emplacement of files accessible by outside apps 149 mode &= 0700; 150 Os.chmod(outFile.getPath(), (int)mode); 151 } catch (ErrnoException e) { 152 e.rethrowAsIOException(); 153 } 154 outFile.setLastModified(mtime); 155 } 156 } 157 } 158