blob: f0a1f2a4978bbf7cc791b8fcc17043e5eee9f78a [file] [log] [blame]
Christopher Tate4a627c72011-04-01 14:43:32 -07001/*
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}