14a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/* 24a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Copyright (C) 2011 The Android Open Source Project 34a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 44a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License"); 54a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * you may not use this file except in compliance with the License. 64a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * You may obtain a copy of the License at 74a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 84a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * http://www.apache.org/licenses/LICENSE-2.0 94a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 104a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Unless required by applicable law or agreed to in writing, software 114a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS, 124a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * See the License for the specific language governing permissions and 144a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * limitations under the License. 154a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */ 164a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 174a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatepackage android.app.backup; 184a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 1975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.os.ParcelFileDescriptor; 2034385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.ErrnoException; 2134385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.Os; 2275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.util.Log; 2375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 2475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.File; 2575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileInputStream; 2675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileOutputStream; 2775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.IOException; 2875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 294a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/** 304a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Global constant definitions et cetera related to the full-backup-to-fd 3179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * binary format. Nothing in this namespace is part of any API; it's all 3279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * hidden details of the current implementation gathered into one location. 334a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 344a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * @hide 354a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */ 364a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatepublic class FullBackup { 3775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate static final String TAG = "FullBackup"; 3875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 3975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String APK_TREE_TOKEN = "a"; 4075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String OBB_TREE_TOKEN = "obb"; 4175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String ROOT_TREE_TOKEN = "r"; 4275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String DATA_TREE_TOKEN = "f"; 43a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate public static final String NO_BACKUP_TREE_TOKEN = "nb"; 4475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String DATABASE_TREE_TOKEN = "db"; 4575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String SHAREDPREFS_TREE_TOKEN = "sp"; 46416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef"; 4775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String CACHE_TREE_TOKEN = "c"; 4875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String SHARED_STORAGE_TOKEN = "shared"; 4975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 5075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String APPS_PREFIX = "apps/"; 51b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/"; 5275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 5375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String FULL_BACKUP_INTENT_ACTION = "fullback"; 5475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String FULL_RESTORE_INTENT_ACTION = "fullrest"; 5575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken"; 5675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 5779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate /** 5879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @hide 5979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate */ 604a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate static public native int backupToTar(String packageName, String domain, 614a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate String linkdomain, String rootpath, String path, BackupDataOutput output); 6275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 6379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate /** 6479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * Copy data from a socket to the given File location on permanent storage. The 65f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate * modification time and access mode of the resulting file will be set if desired, 66f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate * although group/all rwx modes will be stripped: the restored file will not be 67f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate * accessible from outside the target application even if the original file was. 6879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * If the {@code type} parameter indicates that the result should be a directory, 6979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * the socket parameter may be {@code null}; even if it is valid, no data will be 7079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * read from it in this case. 7179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * <p> 7279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * If the {@code mode} argument is negative, then the resulting output file will not 7379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * have its access mode or last modification time reset as part of this operation. 7479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * 7579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @param data Socket supplying the data to be copied to the output file. If the 7679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * output is a directory, this may be {@code null}. 7779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @param size Number of bytes of data to copy from the socket to the file. At least 7879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * this much data must be available through the {@code data} parameter. 7979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @param type Must be either {@link BackupAgent#TYPE_FILE} for ordinary file data 8079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * or {@link BackupAgent#TYPE_DIRECTORY} for a directory. 8179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @param mode Unix-style file mode (as used by the chmod(2) syscall) to be set on 82f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate * the output file or directory. group/all rwx modes are stripped even if set 83f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate * in this parameter. If this parameter is negative then neither 84f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate * the mode nor the mtime values will be applied to the restored file. 8579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @param mtime A timestamp in the standard Unix epoch that will be imposed as the 8679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * last modification time of the output file. if the {@code mode} parameter is 8779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * negative then this parameter will be ignored. 8879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @param outFile Location within the filesystem to place the data. This must point 8946cc43c6fa7623820d4ae9149496cf96bb15f8a3Christopher Tate * to a location that is writeable by the caller, preferably using an absolute path. 9079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * @throws IOException 9179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate */ 9279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate static public void restoreFile(ParcelFileDescriptor data, 9379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate long size, int type, long mode, long mtime, File outFile) throws IOException { 9479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate if (type == BackupAgent.TYPE_DIRECTORY) { 9575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Canonically a directory has no associated content, so we don't need to read 9675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // anything from the pipe in this case. Just create the directory here and 9775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // drop down to the final metadata adjustment. 9875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (outFile != null) outFile.mkdirs(); 9975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } else { 10075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate FileOutputStream out = null; 10175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 10275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Pull the data from the pipe, copying it to the output file, until we're done 10375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate try { 10475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (outFile != null) { 10575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate File parent = outFile.getParentFile(); 10675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (!parent.exists()) { 10775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // in practice this will only be for the default semantic directories, 10875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // and using the default mode for those is appropriate. 10975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate parent.mkdirs(); 11075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out = new FileOutputStream(outFile); 11275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } catch (IOException e) { 11475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e); 11575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 11775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate byte[] buffer = new byte[32 * 1024]; 11875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate final long origSize = size; 11975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate FileInputStream in = new FileInputStream(data.getFileDescriptor()); 12075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate while (size > 0) { 12175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate int toRead = (size > buffer.length) ? buffer.length : (int)size; 12275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate int got = in.read(buffer, 0, toRead); 12375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (got <= 0) { 12475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Log.w(TAG, "Incomplete read: expected " + size + " but got " 12575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate + (origSize - size)); 12675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate break; 12775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 12875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (out != null) { 12975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate try { 13075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out.write(buffer, 0, got); 13175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } catch (IOException e) { 13275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Problem writing to the file. Quit copying data and delete 13375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // the file, but of course keep consuming the input stream. 13475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Log.e(TAG, "Unable to write to file " + outFile.getPath(), e); 13575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out.close(); 13675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out = null; 13775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate outFile.delete(); 13875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 13975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 14075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate size -= got; 14175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 14275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (out != null) out.close(); 14375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 14475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 14575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Now twiddle the state to match the backup, assuming all went well 14679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate if (mode >= 0 && outFile != null) { 14775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate try { 148f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate // explicitly prevent emplacement of files accessible by outside apps 149f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate mode &= 0700; 15034385d352da19805ae948215e2edbeedd16b7941Elliott Hughes Os.chmod(outFile.getPath(), (int)mode); 15175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } catch (ErrnoException e) { 15275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate e.rethrowAsIOException(); 15375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 15475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate outFile.setLastModified(mtime); 15575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 15675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 1574a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate} 158