FullBackup.java revision b0628bfd5aac480a0d412ac96b8af1d97ac01c30
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; 2075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.util.Log; 2175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 2275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.File; 2375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileInputStream; 2475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileOutputStream; 2575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.IOException; 2675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 2775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport libcore.io.ErrnoException; 2875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport libcore.io.Libcore; 2975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 304a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/** 314a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Global constant definitions et cetera related to the full-backup-to-fd 324a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * binary format. 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"; 4375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String DATABASE_TREE_TOKEN = "db"; 4475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String SHAREDPREFS_TREE_TOKEN = "sp"; 4575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String CACHE_TREE_TOKEN = "c"; 4675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String SHARED_STORAGE_TOKEN = "shared"; 4775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 4875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String APPS_PREFIX = "apps/"; 49b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/"; 5075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 5175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String FULL_BACKUP_INTENT_ACTION = "fullback"; 5275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String FULL_RESTORE_INTENT_ACTION = "fullrest"; 5375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken"; 5475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 5575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final int TYPE_EOF = 0; 5675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final int TYPE_FILE = 1; 5775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final int TYPE_DIRECTORY = 2; 5875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate public static final int TYPE_SYMLINK = 3; 594a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 604a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate static public native int backupToTar(String packageName, String domain, 614a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate String linkdomain, String rootpath, String path, BackupDataOutput output); 6275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 6375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate static public void restoreToFile(ParcelFileDescriptor data, 64b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate long size, int type, long mode, long mtime, File outFile, 65b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate boolean doChmod) throws IOException { 6675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (type == FullBackup.TYPE_DIRECTORY) { 6775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Canonically a directory has no associated content, so we don't need to read 6875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // anything from the pipe in this case. Just create the directory here and 6975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // drop down to the final metadata adjustment. 7075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (outFile != null) outFile.mkdirs(); 7175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } else { 7275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate FileOutputStream out = null; 7375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 7475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Pull the data from the pipe, copying it to the output file, until we're done 7575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate try { 7675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (outFile != null) { 7775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate File parent = outFile.getParentFile(); 7875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (!parent.exists()) { 7975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // in practice this will only be for the default semantic directories, 8075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // and using the default mode for those is appropriate. 8175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // TODO: support the edge case of apps that have adjusted the 8275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // permissions on these core directories 8375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate parent.mkdirs(); 8475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 8575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out = new FileOutputStream(outFile); 8675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 8775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } catch (IOException e) { 8875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e); 8975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 9075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 9175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate byte[] buffer = new byte[32 * 1024]; 9275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate final long origSize = size; 9375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate FileInputStream in = new FileInputStream(data.getFileDescriptor()); 9475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate while (size > 0) { 9575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate int toRead = (size > buffer.length) ? buffer.length : (int)size; 9675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate int got = in.read(buffer, 0, toRead); 9775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (got <= 0) { 9875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Log.w(TAG, "Incomplete read: expected " + size + " but got " 9975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate + (origSize - size)); 10075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate break; 10175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 10275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (out != null) { 10375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate try { 10475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out.write(buffer, 0, got); 10575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } catch (IOException e) { 10675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Problem writing to the file. Quit copying data and delete 10775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // the file, but of course keep consuming the input stream. 10875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Log.e(TAG, "Unable to write to file " + outFile.getPath(), e); 10975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out.close(); 11075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate out = null; 11175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate outFile.delete(); 11275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate size -= got; 11575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate if (out != null) out.close(); 11775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 11875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate 11975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate // Now twiddle the state to match the backup, assuming all went well 120b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate if (doChmod && outFile != null) { 12175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate try { 12275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate Libcore.os.chmod(outFile.getPath(), (int)mode); 12375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } catch (ErrnoException e) { 12475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate e.rethrowAsIOException(); 12575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 12675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate outFile.setLastModified(mtime); 12775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 12875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate } 1294a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate} 130