FullBackupAgent.java revision 4a627c71ff53a4fca1f961f4b1dcc0461df18a06
1/* 2 * Copyright (C) 2009 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 17package android.app.backup; 18 19import android.content.pm.ApplicationInfo; 20import android.content.pm.PackageManager; 21import android.os.Environment; 22import android.os.ParcelFileDescriptor; 23import android.util.Log; 24 25import libcore.io.Libcore; 26import libcore.io.ErrnoException; 27import libcore.io.OsConstants; 28import libcore.io.StructStat; 29 30import java.io.File; 31import java.util.HashSet; 32import java.util.LinkedList; 33 34/** 35 * Backs up an application's entire /data/data/<package>/... file system. This 36 * class is used by the desktop full backup mechanism and is not intended for direct 37 * use by applications. 38 * 39 * {@hide} 40 */ 41 42public class FullBackupAgent extends BackupAgent { 43 // !!! TODO: turn off debugging 44 private static final String TAG = "FullBackupAgent"; 45 private static final boolean DEBUG = true; 46 47 PackageManager mPm; 48 49 private String mMainDir; 50 private String mFilesDir; 51 private String mDatabaseDir; 52 private String mSharedPrefsDir; 53 private String mCacheDir; 54 private String mLibDir; 55 56 @Override 57 public void onCreate() { 58 mPm = getPackageManager(); 59 try { 60 ApplicationInfo appInfo = mPm.getApplicationInfo(getPackageName(), 0); 61 mMainDir = new File(appInfo.dataDir).getAbsolutePath(); 62 } catch (PackageManager.NameNotFoundException e) { 63 Log.e(TAG, "Unable to find package " + getPackageName()); 64 throw new RuntimeException(e); 65 } 66 67 mFilesDir = getFilesDir().getAbsolutePath(); 68 mDatabaseDir = getDatabasePath("foo").getParentFile().getAbsolutePath(); 69 mSharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getAbsolutePath(); 70 mCacheDir = getCacheDir().getAbsolutePath(); 71 72 ApplicationInfo app = getApplicationInfo(); 73 mLibDir = (app.nativeLibraryDir != null) 74 ? new File(app.nativeLibraryDir).getAbsolutePath() 75 : null; 76 } 77 78 @Override 79 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 80 ParcelFileDescriptor newState) { 81 // Filters, the scan queue, and the set of resulting entities 82 HashSet<String> filterSet = new HashSet<String>(); 83 84 // Okay, start with the app's root tree, but exclude all of the canonical subdirs 85 if (mLibDir != null) { 86 filterSet.add(mLibDir); 87 } 88 filterSet.add(mCacheDir); 89 filterSet.add(mDatabaseDir); 90 filterSet.add(mSharedPrefsDir); 91 filterSet.add(mFilesDir); 92 processTree(FullBackup.ROOT_TREE_TOKEN, mMainDir, filterSet, data); 93 94 // Now do the same for the files dir, db dir, and shared prefs dir 95 filterSet.add(mMainDir); 96 filterSet.remove(mFilesDir); 97 processTree(FullBackup.DATA_TREE_TOKEN, mFilesDir, filterSet, data); 98 99 filterSet.add(mFilesDir); 100 filterSet.remove(mDatabaseDir); 101 processTree(FullBackup.DATABASE_TREE_TOKEN, mDatabaseDir, filterSet, data); 102 103 filterSet.add(mDatabaseDir); 104 filterSet.remove(mSharedPrefsDir); 105 processTree(FullBackup.SHAREDPREFS_TREE_TOKEN, mSharedPrefsDir, filterSet, data); 106 } 107 108 private void processTree(String domain, String rootPath, 109 HashSet<String> excludes, BackupDataOutput data) { 110 // Scan the dir tree (if it actually exists) and process each entry we find 111 File rootFile = new File(rootPath); 112 if (rootFile.exists()) { 113 LinkedList<File> scanQueue = new LinkedList<File>(); 114 scanQueue.add(rootFile); 115 116 while (scanQueue.size() > 0) { 117 File file = scanQueue.remove(0); 118 String filePath = file.getAbsolutePath(); 119 120 // prune this subtree? 121 if (excludes.contains(filePath)) { 122 continue; 123 } 124 125 // If it's a directory, enqueue its contents for scanning. 126 try { 127 StructStat stat = Libcore.os.lstat(filePath); 128 if (OsConstants.S_ISLNK(stat.st_mode)) { 129 if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file); 130 continue; 131 } else if (OsConstants.S_ISDIR(stat.st_mode)) { 132 File[] contents = file.listFiles(); 133 if (contents != null) { 134 for (File entry : contents) { 135 scanQueue.add(0, entry); 136 } 137 } 138 } 139 } catch (ErrnoException e) { 140 if (DEBUG) Log.w(TAG, "Error scanning file " + file + " : " + e); 141 continue; 142 } 143 144 // Finally, back this file up before proceeding 145 FullBackup.backupToTar(getPackageName(), domain, null, rootPath, filePath, data); 146 } 147 } 148 } 149 150 @Override 151 void onSaveApk(BackupDataOutput data) { 152 ApplicationInfo app = getApplicationInfo(); 153 if (DEBUG) Log.i(TAG, "APK flags: system=" + ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) 154 + " updated=" + ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) 155 + " locked=" + ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) ); 156 if (DEBUG) Log.i(TAG, "codepath: " + getPackageCodePath()); 157 158 // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here 159 final String pkgName = getPackageName(); 160 final String apkDir = new File(getPackageCodePath()).getParent(); 161 FullBackup.backupToTar(pkgName, FullBackup.APK_TREE_TOKEN, null, 162 apkDir, getPackageCodePath(), data); 163 164 // Save associated .obb content if it exists and we did save the apk 165 // check for .obb and save those too 166 final File obbDir = Environment.getExternalStorageAppObbDirectory(pkgName); 167 if (obbDir != null) { 168 if (DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath()); 169 File[] obbFiles = obbDir.listFiles(); 170 if (obbFiles != null) { 171 final String obbDirName = obbDir.getAbsolutePath(); 172 for (File obb : obbFiles) { 173 FullBackup.backupToTar(pkgName, FullBackup.OBB_TREE_TOKEN, null, 174 obbDirName, obb.getAbsolutePath(), data); 175 } 176 } 177 } 178 } 179 180 @Override 181 public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) { 182 } 183} 184