summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt94
-rw-r--r--core/java/android/app/ActivityThread.java11
-rw-r--r--core/java/android/app/IBackupAgent.aidl20
-rw-r--r--core/java/android/app/backup/BackupAgent.java289
-rw-r--r--core/java/android/app/backup/FullBackup.java49
-rw-r--r--core/java/android/app/backup/FullBackupAgent.java192
-rw-r--r--core/java/android/app/backup/FullBackupDataOutput.java21
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java11
-rw-r--r--core/java/android/content/pm/PackageParser.java11
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/values/attrs_manifest.xml8
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--packages/SettingsProvider/AndroidManifest.xml1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java109
-rw-r--r--packages/SharedStorageBackup/AndroidManifest.xml2
-rw-r--r--packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java21
-rw-r--r--services/java/com/android/server/BackupManagerService.java73
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java2
18 files changed, 530 insertions, 387 deletions
diff --git a/api/current.txt b/api/current.txt
index d009a64..d7e3cb3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -183,14 +183,14 @@ package android {
public static final class R.attr {
ctor public R.attr();
field public static final int absListViewStyle = 16842858; // 0x101006a
- field public static final int accessibilityEventTypes = 16843650; // 0x1010382
- field public static final int accessibilityFeedbackType = 16843652; // 0x1010384
- field public static final int accessibilityFlags = 16843654; // 0x1010386
+ field public static final int accessibilityEventTypes = 16843649; // 0x1010381
+ field public static final int accessibilityFeedbackType = 16843651; // 0x1010383
+ field public static final int accessibilityFlags = 16843653; // 0x1010385
field public static final int accountPreferences = 16843423; // 0x101029f
field public static final int accountType = 16843407; // 0x101028f
field public static final int action = 16842797; // 0x101002d
field public static final int actionBarSize = 16843499; // 0x10102eb
- field public static final int actionBarSplitStyle = 16843676; // 0x101039c
+ field public static final int actionBarSplitStyle = 16843675; // 0x101039b
field public static final int actionBarStyle = 16843470; // 0x10102ce
field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
field public static final int actionBarTabStyle = 16843507; // 0x10102f3
@@ -206,9 +206,9 @@ package android {
field public static final int actionModeCopyDrawable = 16843538; // 0x1010312
field public static final int actionModeCutDrawable = 16843537; // 0x1010311
field public static final int actionModePasteDrawable = 16843539; // 0x1010313
- field public static final int actionModeSelectAllDrawable = 16843648; // 0x1010380
+ field public static final int actionModeSelectAllDrawable = 16843647; // 0x101037f
field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
- field public static final int actionProviderClass = 16843678; // 0x101039e
+ field public static final int actionProviderClass = 16843677; // 0x101039d
field public static final int actionViewClass = 16843516; // 0x10102fc
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
@@ -220,7 +220,7 @@ package android {
field public static final int alertDialogIcon = 16843605; // 0x1010355
field public static final int alertDialogStyle = 16842845; // 0x101005d
field public static final int alertDialogTheme = 16843529; // 0x1010309
- field public static final int alignmentMode = 16843642; // 0x101037a
+ field public static final int alignmentMode = 16843641; // 0x1010379
field public static final int allContactsName = 16843468; // 0x10102cc
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
@@ -262,7 +262,7 @@ package android {
field public static final int borderlessButtonStyle = 16843563; // 0x101032b
field public static final int bottom = 16843184; // 0x10101b0
field public static final int bottomBright = 16842957; // 0x10100cd
- field public static final int bottomChevronDrawable = 16843661; // 0x101038d
+ field public static final int bottomChevronDrawable = 16843660; // 0x101038c
field public static final int bottomDark = 16842953; // 0x10100c9
field public static final int bottomLeftRadius = 16843179; // 0x10101ab
field public static final int bottomMedium = 16842958; // 0x10100ce
@@ -281,7 +281,7 @@ package android {
field public static final int cacheColorHint = 16843009; // 0x1010101
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
- field public static final int canRetrieveWindowContent = 16843655; // 0x1010387
+ field public static final int canRetrieveWindowContent = 16843654; // 0x1010386
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
field public static final deprecated int capitalize = 16843113; // 0x1010169
field public static final int centerBright = 16842956; // 0x10100cc
@@ -314,9 +314,9 @@ package android {
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
- field public static final int columnCount = 16843639; // 0x1010377
+ field public static final int columnCount = 16843638; // 0x1010376
field public static final int columnDelay = 16843215; // 0x10101cf
- field public static final int columnOrderPreserved = 16843640; // 0x1010378
+ field public static final int columnOrderPreserved = 16843639; // 0x1010377
field public static final int columnWidth = 16843031; // 0x1010117
field public static final int compatibleWidthLimitDp = 16843621; // 0x1010365
field public static final int completionHint = 16843122; // 0x1010172
@@ -429,7 +429,7 @@ package android {
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
- field public static final int feedbackCount = 16843667; // 0x1010393
+ field public static final int feedbackCount = 16843666; // 0x1010392
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillEnabled = 16843343; // 0x101024f
@@ -462,7 +462,6 @@ package android {
field public static final int fromXScale = 16843202; // 0x10101c2
field public static final int fromYDelta = 16843208; // 0x10101c8
field public static final int fromYScale = 16843204; // 0x10101c4
- field public static final int fullBackupAgent = 16843635; // 0x1010373
field public static final int fullBright = 16842954; // 0x10100ca
field public static final int fullDark = 16842950; // 0x10100c6
field public static final int functionalTest = 16842787; // 0x1010023
@@ -483,7 +482,7 @@ package android {
field public static final int hand_hour = 16843011; // 0x1010103
field public static final int hand_minute = 16843012; // 0x1010104
field public static final int handle = 16843354; // 0x101025a
- field public static final int handleDrawable = 16843657; // 0x1010389
+ field public static final int handleDrawable = 16843656; // 0x1010388
field public static final int handleProfiling = 16842786; // 0x1010022
field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
field public static final int hardwareAccelerated = 16843475; // 0x10102d3
@@ -492,12 +491,12 @@ package android {
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
field public static final int hint = 16843088; // 0x1010150
- field public static final int hitRadius = 16843664; // 0x1010390
+ field public static final int hitRadius = 16843663; // 0x101038f
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
field public static final int horizontalDivider = 16843053; // 0x101012d
field public static final int horizontalGap = 16843327; // 0x101023f
- field public static final int horizontalOffset = 16843669; // 0x1010395
+ field public static final int horizontalOffset = 16843668; // 0x1010394
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
@@ -543,7 +542,7 @@ package android {
field public static final int installLocation = 16843447; // 0x10102b7
field public static final int interpolator = 16843073; // 0x1010141
field public static final int isAlwaysSyncable = 16843571; // 0x1010333
- field public static final int isAuxiliary = 16843649; // 0x1010381
+ field public static final int isAuxiliary = 16843648; // 0x1010380
field public static final int isDefault = 16843297; // 0x1010221
field public static final int isIndicator = 16843079; // 0x1010147
field public static final int isModifier = 16843334; // 0x1010246
@@ -597,30 +596,30 @@ package android {
field public static final int layout_centerInParent = 16843151; // 0x101018f
field public static final int layout_centerVertical = 16843153; // 0x1010191
field public static final int layout_column = 16843084; // 0x101014c
- field public static final int layout_columnSpan = 16843645; // 0x101037d
+ field public static final int layout_columnSpan = 16843644; // 0x101037c
field public static final int layout_gravity = 16842931; // 0x10100b3
field public static final int layout_height = 16842997; // 0x10100f5
- field public static final int layout_heightSpec = 16843647; // 0x101037f
+ field public static final int layout_heightSpec = 16843646; // 0x101037e
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
- field public static final int layout_marginEnd = 16843675; // 0x101039b
+ field public static final int layout_marginEnd = 16843674; // 0x101039a
field public static final int layout_marginLeft = 16842999; // 0x10100f7
field public static final int layout_marginRight = 16843001; // 0x10100f9
- field public static final int layout_marginStart = 16843674; // 0x101039a
+ field public static final int layout_marginStart = 16843673; // 0x1010399
field public static final int layout_marginTop = 16843000; // 0x10100f8
- field public static final int layout_row = 16843643; // 0x101037b
- field public static final int layout_rowSpan = 16843644; // 0x101037c
+ field public static final int layout_row = 16843642; // 0x101037a
+ field public static final int layout_rowSpan = 16843643; // 0x101037b
field public static final int layout_scale = 16843155; // 0x1010193
field public static final int layout_span = 16843085; // 0x101014d
field public static final int layout_toLeftOf = 16843138; // 0x1010182
field public static final int layout_toRightOf = 16843139; // 0x1010183
field public static final int layout_weight = 16843137; // 0x1010181
field public static final int layout_width = 16842996; // 0x10100f4
- field public static final int layout_widthSpec = 16843646; // 0x101037e
+ field public static final int layout_widthSpec = 16843645; // 0x101037d
field public static final int layout_x = 16843135; // 0x101017f
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
- field public static final int leftChevronDrawable = 16843658; // 0x101038a
+ field public static final int leftChevronDrawable = 16843657; // 0x1010389
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
field public static final int lines = 16843092; // 0x1010154
@@ -632,8 +631,8 @@ package android {
field public static final int listDividerAlertDialog = 16843525; // 0x1010305
field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
field public static final int listPreferredItemHeight = 16842829; // 0x101004d
- field public static final int listPreferredItemHeightLarge = 16843670; // 0x1010396
- field public static final int listPreferredItemHeightSmall = 16843671; // 0x1010397
+ field public static final int listPreferredItemHeightLarge = 16843669; // 0x1010395
+ field public static final int listPreferredItemHeightSmall = 16843670; // 0x1010396
field public static final int listSelector = 16843003; // 0x10100fb
field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
field public static final int listViewStyle = 16842868; // 0x1010074
@@ -679,7 +678,7 @@ package android {
field public static final int nextFocusUp = 16842979; // 0x10100e3
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
- field public static final int notificationTimeout = 16843653; // 0x1010385
+ field public static final int notificationTimeout = 16843652; // 0x1010384
field public static final int numColumns = 16843032; // 0x1010118
field public static final int numStars = 16843076; // 0x1010144
field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -693,17 +692,17 @@ package android {
field public static final int orderingFromXml = 16843239; // 0x10101e7
field public static final int orientation = 16842948; // 0x10100c4
field public static final int outAnimation = 16843128; // 0x1010178
- field public static final int outerRadius = 16843663; // 0x101038f
+ field public static final int outerRadius = 16843662; // 0x101038e
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
- field public static final int packageNames = 16843651; // 0x1010383
+ field public static final int packageNames = 16843650; // 0x1010382
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
- field public static final int paddingEnd = 16843673; // 0x1010399
+ field public static final int paddingEnd = 16843672; // 0x1010398
field public static final int paddingLeft = 16842966; // 0x10100d6
field public static final int paddingRight = 16842968; // 0x10100d8
- field public static final int paddingStart = 16843672; // 0x1010398
+ field public static final int paddingStart = 16843671; // 0x1010397
field public static final int paddingTop = 16842967; // 0x10100d7
field public static final int panelBackground = 16842846; // 0x101005e
field public static final int panelColorBackground = 16842849; // 0x1010061
@@ -784,17 +783,17 @@ package android {
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
field public static final int right = 16843183; // 0x10101af
- field public static final int rightChevronDrawable = 16843659; // 0x101038b
+ field public static final int rightChevronDrawable = 16843658; // 0x101038a
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
- field public static final int rowCount = 16843637; // 0x1010375
+ field public static final int rowCount = 16843636; // 0x1010374
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
field public static final int rowHeight = 16843058; // 0x1010132
- field public static final int rowOrderPreserved = 16843638; // 0x1010376
+ field public static final int rowOrderPreserved = 16843637; // 0x1010375
field public static final int saveEnabled = 16842983; // 0x10100e7
field public static final int scaleGravity = 16843262; // 0x10101fe
field public static final int scaleHeight = 16843261; // 0x10101fd
@@ -860,7 +859,7 @@ package android {
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
- field public static final int snapMargin = 16843666; // 0x1010392
+ field public static final int snapMargin = 16843665; // 0x1010391
field public static final int soundEffectsEnabled = 16843285; // 0x1010215
field public static final int spacing = 16843027; // 0x1010113
field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087
@@ -908,7 +907,7 @@ package android {
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int suggestActionMsg = 16843228; // 0x10101dc
field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
- field public static final int suggestionsEnabled = 16843636; // 0x1010374
+ field public static final int suggestionsEnabled = 16843635; // 0x1010373
field public static final int summary = 16843241; // 0x10101e9
field public static final int summaryColumn = 16843426; // 0x10102a2
field public static final int summaryOff = 16843248; // 0x10101f0
@@ -925,7 +924,7 @@ package android {
field public static final int tag = 16842961; // 0x10100d1
field public static final int targetActivity = 16843266; // 0x1010202
field public static final int targetClass = 16842799; // 0x101002f
- field public static final int targetDrawables = 16843656; // 0x1010388
+ field public static final int targetDrawables = 16843655; // 0x1010387
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
@@ -976,7 +975,7 @@ package android {
field public static final int textColorTertiary = 16843282; // 0x1010212
field public static final int textColorTertiaryInverse = 16843283; // 0x1010213
field public static final int textCursorDrawable = 16843618; // 0x1010362
- field public static final int textDirection = 16843677; // 0x101039d
+ field public static final int textDirection = 16843676; // 0x101039c
field public static final int textEditNoPasteWindowLayout = 16843541; // 0x1010315
field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314
field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f
@@ -1016,7 +1015,7 @@ package android {
field public static final int toYScale = 16843205; // 0x10101c5
field public static final int top = 16843182; // 0x10101ae
field public static final int topBright = 16842955; // 0x10100cb
- field public static final int topChevronDrawable = 16843660; // 0x101038c
+ field public static final int topChevronDrawable = 16843659; // 0x101038b
field public static final int topDark = 16842951; // 0x10100c7
field public static final int topLeftRadius = 16843177; // 0x10101a9
field public static final int topOffset = 16843352; // 0x1010258
@@ -1032,7 +1031,7 @@ package android {
field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
- field public static final int useDefaultMargins = 16843641; // 0x1010379
+ field public static final int useDefaultMargins = 16843640; // 0x1010378
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
field public static final int userVisible = 16843409; // 0x1010291
@@ -1046,10 +1045,10 @@ package android {
field public static final int verticalCorrection = 16843322; // 0x101023a
field public static final int verticalDivider = 16843054; // 0x101012e
field public static final int verticalGap = 16843328; // 0x1010240
- field public static final int verticalOffset = 16843668; // 0x1010394
+ field public static final int verticalOffset = 16843667; // 0x1010393
field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
field public static final int verticalSpacing = 16843029; // 0x1010115
- field public static final int vibrationDuration = 16843665; // 0x1010391
+ field public static final int vibrationDuration = 16843664; // 0x1010390
field public static final int visibility = 16842972; // 0x10100dc
field public static final int visible = 16843156; // 0x1010194
field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1066,7 +1065,7 @@ package android {
field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298
field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293
field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294
- field public static final int waveDrawable = 16843662; // 0x101038e
+ field public static final int waveDrawable = 16843661; // 0x101038d
field public static final int webTextViewStyle = 16843449; // 0x10102b9
field public static final int webViewStyle = 16842885; // 0x1010085
field public static final int weekDayTextAppearance = 16843592; // 0x1010348
@@ -3737,7 +3736,11 @@ package android.app.backup {
method public abstract void onBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor) throws java.io.IOException;
method public void onCreate();
method public void onDestroy();
+ method public void onFullBackup(android.app.backup.FullBackupDataOutput) throws java.io.IOException;
method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
+ field public static final int TYPE_DIRECTORY = 2; // 0x2
+ field public static final int TYPE_FILE = 1; // 0x1
}
public class BackupAgentHelper extends android.app.backup.BackupAgent {
@@ -3789,6 +3792,9 @@ package android.app.backup {
method public void writeNewStateDescription(android.os.ParcelFileDescriptor);
}
+ public class FullBackupDataOutput {
+ }
+
public abstract class RestoreObserver {
ctor public RestoreObserver();
method public void onUpdate(int, java.lang.String);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1ec7a96..eee14fb 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2013,15 +2013,10 @@ public final class ActivityThread {
BackupAgent agent = null;
String classname = data.appInfo.backupAgentName;
- if (data.backupMode == IApplicationThread.BACKUP_MODE_FULL
- || data.backupMode == IApplicationThread.BACKUP_MODE_RESTORE_FULL) {
+ // full backup operation but no app-supplied agent? use the default implementation
+ if (classname == null && (data.backupMode == IApplicationThread.BACKUP_MODE_FULL
+ || data.backupMode == IApplicationThread.BACKUP_MODE_RESTORE_FULL)) {
classname = "android.app.backup.FullBackupAgent";
- if ((data.appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- // system packages can supply their own full-backup agent
- if (data.appInfo.fullBackupAgentName != null) {
- classname = data.appInfo.fullBackupAgentName;
- }
- }
}
try {
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index 8af78fa..087f83c 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -51,7 +51,6 @@ oneway interface IBackupAgent {
void doBackup(in ParcelFileDescriptor oldState,
in ParcelFileDescriptor data,
in ParcelFileDescriptor newState,
- boolean storeApk,
int token, IBackupManager callbackBinder);
/**
@@ -81,6 +80,25 @@ oneway interface IBackupAgent {
in ParcelFileDescriptor newState, int token, IBackupManager callbackBinder);
/**
+ * Perform a "full" backup to the given file descriptor. The output file is presumed
+ * to be a socket or other non-seekable, write-only data sink. When this method is
+ * called, the app should write all of its files to the output.
+ *
+ * @param data Write-only file to receive the backed-up file content stream.
+ * The data must be formatted correctly for the resulting archive to be
+ * legitimate, so that will be tightly controlled by the available API.
+ *
+ * @param token Opaque token identifying this transaction. This must
+ * be echoed back to the backup service binder once the agent is
+ * finished restoring the application based on the restore data
+ * contents.
+ *
+ * @param callbackBinder Binder on which to indicate operation completion,
+ * passed here as a convenience to the agent.
+ */
+ void doFullBackup(in ParcelFileDescriptor data, int token, IBackupManager callbackBinder);
+
+ /**
* Restore a single "file" to the application. The file was typically obtained from
* a full-backup dataset. The agent reads 'size' bytes of file content
* from the provided file descriptor.
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 63f3258..65c73f9 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -20,13 +20,22 @@ import android.app.IBackupAgent;
import android.app.backup.IBackupManager;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
+import java.io.File;
import java.io.IOException;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.OsConstants;
+import libcore.io.StructStat;
/**
* Provides the central interface between an
@@ -87,6 +96,24 @@ public abstract class BackupAgent extends ContextWrapper {
private static final String TAG = "BackupAgent";
private static final boolean DEBUG = true;
+ /** @hide */
+ public static final int TYPE_EOF = 0;
+
+ /**
+ * During a full restore, indicates that the file system object being restored
+ * is an ordinary file.
+ */
+ public static final int TYPE_FILE = 1;
+
+ /**
+ * During a full restore, indicates that the file system object being restored
+ * is a directory.
+ */
+ public static final int TYPE_DIRECTORY = 2;
+
+ /** @hide */
+ public static final int TYPE_SYMLINK = 3;
+
public BackupAgent() {
super(null);
}
@@ -179,18 +206,240 @@ public abstract class BackupAgent extends ContextWrapper {
throws IOException;
/**
+ * The default implementation backs up the entirety of the application's "owned"
+ * file system trees to the output.
+ */
+ public void onFullBackup(FullBackupDataOutput data) throws IOException {
+ ApplicationInfo appInfo = getApplicationInfo();
+
+ String rootDir = new File(appInfo.dataDir).getAbsolutePath();
+ String filesDir = getFilesDir().getAbsolutePath();
+ String databaseDir = getDatabasePath("foo").getParentFile().getAbsolutePath();
+ String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getAbsolutePath();
+ String cacheDir = getCacheDir().getAbsolutePath();
+ String libDir = (appInfo.nativeLibraryDir != null)
+ ? new File(appInfo.nativeLibraryDir).getAbsolutePath()
+ : null;
+
+ // Filters, the scan queue, and the set of resulting entities
+ HashSet<String> filterSet = new HashSet<String>();
+ String packageName = getPackageName();
+
+ // Okay, start with the app's root tree, but exclude all of the canonical subdirs
+ if (libDir != null) {
+ filterSet.add(libDir);
+ }
+ filterSet.add(cacheDir);
+ filterSet.add(databaseDir);
+ filterSet.add(sharedPrefsDir);
+ filterSet.add(filesDir);
+ fullBackupFileTree(packageName, FullBackup.ROOT_TREE_TOKEN, rootDir, filterSet, data);
+
+ // Now do the same for the files dir, db dir, and shared prefs dir
+ filterSet.add(rootDir);
+ filterSet.remove(filesDir);
+ fullBackupFileTree(packageName, FullBackup.DATA_TREE_TOKEN, filesDir, filterSet, data);
+
+ filterSet.add(filesDir);
+ filterSet.remove(databaseDir);
+ fullBackupFileTree(packageName, FullBackup.DATABASE_TREE_TOKEN, databaseDir, filterSet, data);
+
+ filterSet.add(databaseDir);
+ filterSet.remove(sharedPrefsDir);
+ fullBackupFileTree(packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, sharedPrefsDir, filterSet, data);
+ }
+
+ /**
+ * Write an entire file as part of a full-backup operation. The file's contents
+ * will be delivered to the backup destination along with the metadata necessary
+ * to place it with the proper location and permissions on the device where the
+ * data is restored.
* @hide
+ *
+ * @param context The BackupAgent that is calling this method. It is an error to
+ * call it from something other than a running BackupAgent instance.
+ * @param file The file to be backed up. The file must exist and be readable by
+ * the caller.
+ * @param output The destination to which the backed-up file data will be sent.
+ */
+ public final void fullBackupFile(File file, FullBackupDataOutput output) {
+ // Look up where all of our various well-defined dir trees live on this device
+ String mainDir;
+ String filesDir;
+ String dbDir;
+ String spDir;
+ String cacheDir;
+ String libDir;
+
+ ApplicationInfo appInfo = getApplicationInfo();
+
+ mainDir = new File(appInfo.dataDir).getAbsolutePath();
+ filesDir = getFilesDir().getAbsolutePath();
+ dbDir = getDatabasePath("foo").getParentFile().getAbsolutePath();
+ spDir = getSharedPrefsFile("foo").getParentFile().getAbsolutePath();
+ cacheDir = getCacheDir().getAbsolutePath();
+ libDir = (appInfo.nativeLibraryDir == null) ? null
+ : new File(appInfo.nativeLibraryDir).getAbsolutePath();
+
+ // Now figure out which well-defined tree the file is placed in, working from
+ // most to least specific. We also specifically exclude the lib and cache dirs.
+ String filePath = file.getAbsolutePath();
+
+ if (filePath.startsWith(cacheDir) || filePath.startsWith(libDir)) {
+ Log.w(TAG, "lib and cache files are not backed up");
+ return;
+ }
+
+ final String domain;
+ String rootpath = null;
+ if (filePath.startsWith(dbDir)) {
+ domain = FullBackup.DATABASE_TREE_TOKEN;
+ rootpath = dbDir;
+ } else if (filePath.startsWith(spDir)) {
+ domain = FullBackup.SHAREDPREFS_TREE_TOKEN;
+ rootpath = spDir;
+ } else if (filePath.startsWith(filesDir)) {
+ domain = FullBackup.DATA_TREE_TOKEN;
+ rootpath = filesDir;
+ } else if (filePath.startsWith(mainDir)) {
+ domain = FullBackup.ROOT_TREE_TOKEN;
+ rootpath = mainDir;
+ } else {
+ Log.w(TAG, "File " + filePath + " is in an unsupported location; skipping");
+ return;
+ }
+
+ // And now that we know where it lives, semantically, back it up appropriately
+ Log.i(TAG, "backupFile() of " + filePath + " => domain=" + domain
+ + " rootpath=" + rootpath);
+ FullBackup.backupToTar(getPackageName(), domain, null, rootpath, filePath,
+ output.getData());
+ }
+
+ /**
+ * Scan the dir tree (if it actually exists) and process each entry we find. If the
+ * 'excludes' parameter is non-null, it is consulted each time a new file system entity
+ * is visited to see whether that entity (and its subtree, if appropriate) should be
+ * omitted from the backup process.
+ *
+ * @hide
+ */
+ protected final void fullBackupFileTree(String packageName, String domain, String rootPath,
+ HashSet<String> excludes, FullBackupDataOutput output) {
+ File rootFile = new File(rootPath);
+ if (rootFile.exists()) {
+ LinkedList<File> scanQueue = new LinkedList<File>();
+ scanQueue.add(rootFile);
+
+ while (scanQueue.size() > 0) {
+ File file = scanQueue.remove(0);
+ String filePath = file.getAbsolutePath();
+
+ // prune this subtree?
+ if (excludes != null && excludes.contains(filePath)) {
+ continue;
+ }
+
+ // If it's a directory, enqueue its contents for scanning.
+ try {
+ StructStat stat = Libcore.os.lstat(filePath);
+ if (OsConstants.S_ISLNK(stat.st_mode)) {
+ if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
+ continue;
+ } else if (OsConstants.S_ISDIR(stat.st_mode)) {
+ File[] contents = file.listFiles();
+ if (contents != null) {
+ for (File entry : contents) {
+ scanQueue.add(0, entry);
+ }
+ }
+ }
+ } catch (ErrnoException e) {
+ if (DEBUG) Log.w(TAG, "Error scanning file " + file + " : " + e);
+ continue;
+ }
+
+ // Finally, back this file up before proceeding
+ FullBackup.backupToTar(packageName, domain, null, rootPath, filePath,
+ output.getData());
+ }
+ }
+ }
+
+ /**
+ * Handle the data delivered via the given file descriptor during a full restore
+ * operation. The agent is given the path to the file's original location as well
+ * as its size and metadata.
+ * <p>
+ * The file descriptor can only be read for {@code size} bytes; attempting to read
+ * more data has undefined behavior.
+ * <p>
+ * The default implementation creates the destination file/directory and populates it
+ * with the data from the file descriptor, then sets the file's access mode and
+ * modification time to match the restore arguments.
+ *
+ * @param data A read-only file descriptor from which the agent can read {@code size}
+ * bytes of file data.
+ * @param size The number of bytes of file content to be restored to the given
+ * destination. If the file system object being restored is a directory, {@code size}
+ * will be zero.
+ * @param destination The File on disk to be restored with the given data.
+ * @param type The kind of file system object being restored. This will be either
+ * {@link BackupAgent#TYPE_FILE} or {@link BackupAgent#TYPE_DIRECTORY}.
+ * @param mode The access mode to be assigned to the destination after its data is
+ * written. This is in the standard format used by {@code chmod()}.
+ * @param mtime The modification time of the file when it was backed up, suitable to
+ * be assigned to the file after its data is written.
+ * @throws IOException
*/
public void onRestoreFile(ParcelFileDescriptor data, long size,
- int type, String domain, String path, long mode, long mtime)
+ File destination, int type, long mode, long mtime)
throws IOException {
- // empty stub implementation
+ FullBackup.restoreFile(data, size, type, mode, mtime, destination);
}
/**
- * Package-private, used only for dispatching an extra step during full backup
+ * Only specialized platform agents should overload this entry point to support
+ * restores to crazy non-app locations.
+ * @hide
*/
- void onSaveApk(BackupDataOutput data) {
+ protected void onRestoreFile(ParcelFileDescriptor data, long size,
+ int type, String domain, String path, long mode, long mtime)
+ throws IOException {
+ String basePath = null;
+
+ if (DEBUG) Log.d(TAG, "onRestoreFile() size=" + size + " type=" + type
+ + " domain=" + domain + " relpath=" + path + " mode=" + mode
+ + " mtime=" + mtime);
+
+ // Parse out the semantic domains into the correct physical location
+ if (domain.equals(FullBackup.DATA_TREE_TOKEN)) {
+ basePath = getFilesDir().getAbsolutePath();
+ } else if (domain.equals(FullBackup.DATABASE_TREE_TOKEN)) {
+ basePath = getDatabasePath("foo").getParentFile().getAbsolutePath();
+ } else if (domain.equals(FullBackup.ROOT_TREE_TOKEN)) {
+ basePath = new File(getApplicationInfo().dataDir).getAbsolutePath();
+ } else if (domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)) {
+ basePath = getSharedPrefsFile("foo").getParentFile().getAbsolutePath();
+ } else if (domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
+ basePath = getCacheDir().getAbsolutePath();
+ } else {
+ // Not a supported location
+ Log.i(TAG, "Data restored from non-app domain " + domain + ", ignoring");
+ }
+
+ // Now that we've figured out where the data goes, send it on its way
+ if (basePath != null) {
+ File outFile = new File(basePath, path);
+ if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outFile.getPath());
+ onRestoreFile(data, size, outFile, type, mode, mtime);
+ } else {
+ // Not a supported output location? We need to consume the data
+ // anyway, so just use the default "copy the data out" implementation
+ // with a null destination.
+ if (DEBUG) Log.i(TAG, "[ skipping data from unsupported domain " + domain + "]");
+ FullBackup.restoreFile(data, size, type, mode, mtime, null);
+ }
}
// ----- Core implementation -----
@@ -215,7 +464,6 @@ public abstract class BackupAgent extends ContextWrapper {
public void doBackup(ParcelFileDescriptor oldState,
ParcelFileDescriptor data,
ParcelFileDescriptor newState,
- boolean storeApk,
int token, IBackupManager callbackBinder) throws RemoteException {
// Ensure that we're running with the app's normal permission level
long ident = Binder.clearCallingIdentity();
@@ -223,10 +471,6 @@ public abstract class BackupAgent extends ContextWrapper {
if (DEBUG) Log.v(TAG, "doBackup() invoked");
BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
- if (storeApk) {
- onSaveApk(output);
- }
-
try {
BackupAgent.this.onBackup(oldState, output, newState);
} catch (IOException ex) {
@@ -273,6 +517,33 @@ public abstract class BackupAgent extends ContextWrapper {
}
@Override
+ public void doFullBackup(ParcelFileDescriptor data,
+ int token, IBackupManager callbackBinder) {
+ // Ensure that we're running with the app's normal permission level
+ long ident = Binder.clearCallingIdentity();
+
+ if (DEBUG) Log.v(TAG, "doFullBackup() invoked");
+ BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
+
+ try {
+ BackupAgent.this.onFullBackup(new FullBackupDataOutput(data));
+ } catch (IOException ex) {
+ Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
+ throw new RuntimeException(ex);
+ } catch (RuntimeException ex) {
+ Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
+ throw ex;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ try {
+ callbackBinder.opComplete(token);
+ } catch (RemoteException e) {
+ // we'll time out anyway, so we're safe
+ }
+ }
+ }
+
+ @Override
public void doRestoreFile(ParcelFileDescriptor data, long size,
int type, String domain, String path, long mode, long mtime,
int token, IBackupManager callbackBinder) throws RemoteException {
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 3b70e19..d7f1c9f 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -16,6 +16,9 @@
package android.app.backup;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -29,7 +32,8 @@ import libcore.io.Libcore;
/**
* Global constant definitions et cetera related to the full-backup-to-fd
- * binary format.
+ * binary format. Nothing in this namespace is part of any API; it's all
+ * hidden details of the current implementation gathered into one location.
*
* @hide
*/
@@ -52,18 +56,41 @@ public class FullBackup {
public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
- public static final int TYPE_EOF = 0;
- public static final int TYPE_FILE = 1;
- public static final int TYPE_DIRECTORY = 2;
- public static final int TYPE_SYMLINK = 3;
-
+ /**
+ * @hide
+ */
static public native int backupToTar(String packageName, String domain,
String linkdomain, String rootpath, String path, BackupDataOutput output);
- static public void restoreToFile(ParcelFileDescriptor data,
- long size, int type, long mode, long mtime, File outFile,
- boolean doChmod) throws IOException {
- if (type == FullBackup.TYPE_DIRECTORY) {
+ /**
+ * Copy data from a socket to the given File location on permanent storage. The
+ * modification time and access mode of the resulting file will be set if desired.
+ * If the {@code type} parameter indicates that the result should be a directory,
+ * the socket parameter may be {@code null}; even if it is valid, no data will be
+ * read from it in this case.
+ * <p>
+ * If the {@code mode} argument is negative, then the resulting output file will not
+ * have its access mode or last modification time reset as part of this operation.
+ *
+ * @param data Socket supplying the data to be copied to the output file. If the
+ * output is a directory, this may be {@code null}.
+ * @param size Number of bytes of data to copy from the socket to the file. At least
+ * this much data must be available through the {@code data} parameter.
+ * @param type Must be either {@link BackupAgent#TYPE_FILE} for ordinary file data
+ * or {@link BackupAgent#TYPE_DIRECTORY} for a directory.
+ * @param mode Unix-style file mode (as used by the chmod(2) syscall) to be set on
+ * the output file or directory. If this parameter is negative then neither
+ * the mode nor the mtime parameters will be used.
+ * @param mtime A timestamp in the standard Unix epoch that will be imposed as the
+ * last modification time of the output file. if the {@code mode} parameter is
+ * negative then this parameter will be ignored.
+ * @param outFile Location within the filesystem to place the data. This must point
+ * to a location that is writeable by the caller, prefereably using an absolute path.
+ * @throws IOException
+ */
+ static public void restoreFile(ParcelFileDescriptor data,
+ long size, int type, long mode, long mtime, File outFile) throws IOException {
+ if (type == BackupAgent.TYPE_DIRECTORY) {
// Canonically a directory has no associated content, so we don't need to read
// anything from the pipe in this case. Just create the directory here and
// drop down to the final metadata adjustment.
@@ -117,7 +144,7 @@ public class FullBackup {
}
// Now twiddle the state to match the backup, assuming all went well
- if (doChmod && outFile != null) {
+ if (mode >= 0 && outFile != null) {
try {
Libcore.os.chmod(outFile.getPath(), (int)mode);
} catch (ErrnoException e) {
diff --git a/core/java/android/app/backup/FullBackupAgent.java b/core/java/android/app/backup/FullBackupAgent.java
index df1c363..faea76a 100644
--- a/core/java/android/app/backup/FullBackupAgent.java
+++ b/core/java/android/app/backup/FullBackupAgent.java
@@ -16,210 +16,26 @@
package android.app.backup;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import libcore.io.Libcore;
-import libcore.io.ErrnoException;
-import libcore.io.OsConstants;
-import libcore.io.StructStat;
-
-import java.io.File;
import java.io.IOException;
-import java.util.HashSet;
-import java.util.LinkedList;
/**
- * Backs up an application's entire /data/data/&lt;package&gt;/... file system. This
- * class is used by the desktop full backup mechanism and is not intended for direct
- * use by applications.
+ * Simple concrete class that merely provides the default BackupAgent full backup/restore
+ * implementations for applications that do not supply their own.
*
* {@hide}
*/
public class FullBackupAgent extends BackupAgent {
- // !!! TODO: turn off debugging
- private static final String TAG = "FullBackupAgent";
- private static final boolean DEBUG = true;
-
- PackageManager mPm;
-
- private String mMainDir;
- private String mFilesDir;
- private String mDatabaseDir;
- private String mSharedPrefsDir;
- private String mCacheDir;
- private String mLibDir;
-
- private File NULL_FILE;
-
- @Override
- public void onCreate() {
- NULL_FILE = new File("/dev/null");
-
- mPm = getPackageManager();
- try {
- ApplicationInfo appInfo = mPm.getApplicationInfo(getPackageName(), 0);
- mMainDir = new File(appInfo.dataDir).getAbsolutePath();
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Unable to find package " + getPackageName());
- throw new RuntimeException(e);
- }
-
- mFilesDir = getFilesDir().getAbsolutePath();
- mDatabaseDir = getDatabasePath("foo").getParentFile().getAbsolutePath();
- mSharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getAbsolutePath();
- mCacheDir = getCacheDir().getAbsolutePath();
-
- ApplicationInfo app = getApplicationInfo();
- mLibDir = (app.nativeLibraryDir != null)
- ? new File(app.nativeLibraryDir).getAbsolutePath()
- : null;
- }
-
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
- // Filters, the scan queue, and the set of resulting entities
- HashSet<String> filterSet = new HashSet<String>();
- String packageName = getPackageName();
-
- // Okay, start with the app's root tree, but exclude all of the canonical subdirs
- if (mLibDir != null) {
- filterSet.add(mLibDir);
- }
- filterSet.add(mCacheDir);
- filterSet.add(mDatabaseDir);
- filterSet.add(mSharedPrefsDir);
- filterSet.add(mFilesDir);
- processTree(packageName, FullBackup.ROOT_TREE_TOKEN, mMainDir, filterSet, data);
-
- // Now do the same for the files dir, db dir, and shared prefs dir
- filterSet.add(mMainDir);
- filterSet.remove(mFilesDir);
- processTree(packageName, FullBackup.DATA_TREE_TOKEN, mFilesDir, filterSet, data);
-
- filterSet.add(mFilesDir);
- filterSet.remove(mDatabaseDir);
- processTree(packageName, FullBackup.DATABASE_TREE_TOKEN, mDatabaseDir, filterSet, data);
-
- filterSet.add(mDatabaseDir);
- filterSet.remove(mSharedPrefsDir);
- processTree(packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, mSharedPrefsDir, filterSet, data);
+ // Doesn't do incremental backup/restore
}
- // Scan the dir tree (if it actually exists) and process each entry we find. If the
- // 'excludes' parameter is non-null, it is consulted each time a new file system entity
- // is visited to see whether that entity (and its subtree, if appropriate) should be
- // omitted from the backup process.
- protected void processTree(String packageName, String domain, String rootPath,
- HashSet<String> excludes, BackupDataOutput data) {
- File rootFile = new File(rootPath);
- if (rootFile.exists()) {
- LinkedList<File> scanQueue = new LinkedList<File>();
- scanQueue.add(rootFile);
-
- while (scanQueue.size() > 0) {
- File file = scanQueue.remove(0);
- String filePath = file.getAbsolutePath();
-
- // prune this subtree?
- if (excludes != null && excludes.contains(filePath)) {
- continue;
- }
-
- // If it's a directory, enqueue its contents for scanning.
- try {
- StructStat stat = Libcore.os.lstat(filePath);
- if (OsConstants.S_ISLNK(stat.st_mode)) {
- if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
- continue;
- } else if (OsConstants.S_ISDIR(stat.st_mode)) {
- File[] contents = file.listFiles();
- if (contents != null) {
- for (File entry : contents) {
- scanQueue.add(0, entry);
- }
- }
- }
- } catch (ErrnoException e) {
- if (DEBUG) Log.w(TAG, "Error scanning file " + file + " : " + e);
- continue;
- }
-
- // Finally, back this file up before proceeding
- FullBackup.backupToTar(packageName, domain, null, rootPath, filePath, data);
- }
- }
- }
-
- @Override
- void onSaveApk(BackupDataOutput data) {
- ApplicationInfo app = getApplicationInfo();
- if (DEBUG) Log.i(TAG, "APK flags: system=" + ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
- + " updated=" + ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)
- + " locked=" + ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) );
- if (DEBUG) Log.i(TAG, "codepath: " + getPackageCodePath());
-
- // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
- final String pkgName = getPackageName();
- final String apkDir = new File(getPackageCodePath()).getParent();
- FullBackup.backupToTar(pkgName, FullBackup.APK_TREE_TOKEN, null,
- apkDir, getPackageCodePath(), data);
-
- // Save associated .obb content if it exists and we did save the apk
- // check for .obb and save those too
- final File obbDir = Environment.getExternalStorageAppObbDirectory(pkgName);
- if (obbDir != null) {
- if (DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
- File[] obbFiles = obbDir.listFiles();
- if (obbFiles != null) {
- final String obbDirName = obbDir.getAbsolutePath();
- for (File obb : obbFiles) {
- FullBackup.backupToTar(pkgName, FullBackup.OBB_TREE_TOKEN, null,
- obbDirName, obb.getAbsolutePath(), data);
- }
- }
- }
- }
-
- /**
- * Dummy -- We're never used for restore of an incremental dataset
- */
@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException {
- }
-
- /**
- * Restore the described file from the given pipe.
- */
- @Override
- public void onRestoreFile(ParcelFileDescriptor data, long size,
- int type, String domain, String relpath, long mode, long mtime)
- throws IOException {
- String basePath = null;
- File outFile = null;
-
- if (DEBUG) Log.d(TAG, "onRestoreFile() size=" + size + " type=" + type
- + " domain=" + domain + " relpath=" + relpath + " mode=" + mode
- + " mtime=" + mtime);
-
- // Parse out the semantic domains into the correct physical location
- if (domain.equals(FullBackup.DATA_TREE_TOKEN)) basePath = mFilesDir;
- else if (domain.equals(FullBackup.DATABASE_TREE_TOKEN)) basePath = mDatabaseDir;
- else if (domain.equals(FullBackup.ROOT_TREE_TOKEN)) basePath = mMainDir;
- else if (domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)) basePath = mSharedPrefsDir;
-
- // Not a supported output location? We need to consume the data
- // anyway, so send it to /dev/null
- outFile = (basePath != null) ? new File(basePath, relpath) : null;
- if (DEBUG) Log.i(TAG, "[" + domain + " : " + relpath + "] mapped to " + outFile.getPath());
-
- // Now that we've figured out where the data goes, send it on its way
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
+ // Doesn't do incremental backup/restore
}
}
diff --git a/core/java/android/app/backup/FullBackupDataOutput.java b/core/java/android/app/backup/FullBackupDataOutput.java
new file mode 100644
index 0000000..99dab1f
--- /dev/null
+++ b/core/java/android/app/backup/FullBackupDataOutput.java
@@ -0,0 +1,21 @@
+package android.app.backup;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Provides the interface through which a {@link BackupAgent} writes entire files
+ * to a full backup data set, via its {@link BackupAgent#onFullBackup(FullBackupDataOutput)}
+ * method.
+ */
+public class FullBackupDataOutput {
+ // Currently a name-scoping shim around BackupDataOutput
+ private BackupDataOutput mData;
+
+ /** @hide */
+ public FullBackupDataOutput(ParcelFileDescriptor fd) {
+ mData = new BackupDataOutput(fd.getFileDescriptor());
+ }
+
+ /** @hide */
+ public BackupDataOutput getData() { return mData; }
+}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 454cb31..ddb6ef0 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -91,15 +91,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public String backupAgentName;
/**
- * Class implementing the package's *full* backup functionality. This
- * is not usable except by system-installed packages. It can be the same
- * as the backupAgent.
- *
- * @hide
- */
- public String fullBackupAgentName;
-
- /**
* Value for {@link #flags}: if set, this application is installed in the
* device's system image.
*/
@@ -555,7 +546,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(installLocation);
dest.writeString(manageSpaceActivityName);
dest.writeString(backupAgentName);
- dest.writeString(fullBackupAgentName);
dest.writeInt(descriptionRes);
}
@@ -593,7 +583,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
installLocation = source.readInt();
manageSpaceActivityName = source.readString();
backupAgentName = source.readString();
- fullBackupAgentName = source.readString();
descriptionRes = source.readInt();
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 208869b..53d6bb1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1517,17 +1517,6 @@ public class PackageParser {
}
}
- // fullBackupAgent is explicitly handled even if allowBackup is false
- name = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestApplication_fullBackupAgent, 0);
- if (name != null) {
- ai.fullBackupAgentName = buildClassName(pkgName, name, outError);
- if (false) {
- Log.v(TAG, "android:fullBackupAgent=" + ai.fullBackupAgentName
- + " from " + pkgName + "+" + name);
- }
- }
-
TypedValue v = sa.peekValue(
com.android.internal.R.styleable.AndroidManifestApplication_label);
if (v != null && (ai.labelRes=v.resourceId) == 0) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1a32060..49eaf19 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1418,7 +1418,6 @@
android:label="@string/android_system_label"
android:allowClearUserData="false"
android:backupAgent="com.android.server.SystemBackupAgent"
- android:fullBackupAgent="com.android.server.SystemBackupAgent"
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android">
<activity android:name="com.android.internal.app.ChooserActivity"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 03b332e..dd16bd0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -696,13 +696,6 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="restoreAnyVersion" format="boolean" />
- <!-- The agent to use for a *full* backup of the package. Only system applications
- can use this to override the ordinary FullBackupAgent with a custom implementation.
- It's needed strictly for packages with strongly device-specific data, such as the
- Settings provider.
- -->
- <attr name="fullBackupAgent" format="string" />
-
<!-- The default install location defined by an application. -->
<attr name="installLocation">
<!-- Let the system decide ideal install location -->
@@ -800,7 +793,6 @@
<attr name="killAfterRestore" />
<attr name="restoreNeedsApplication" />
<attr name="restoreAnyVersion" />
- <attr name="fullBackupAgent" />
<attr name="neverEncrypt" />
<!-- Request that your application's processes be created with
a large Dalvik heap. This applies to <em>all</em> processes
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 54e484e..20f5e7c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1725,7 +1725,6 @@
<public type="attr" name="layoutDirection" />
- <public type="attr" name="fullBackupAgent" />
<public type="attr" name="suggestionsEnabled" />
<public type="attr" name="rowCount" />
@@ -1737,7 +1736,6 @@
<public type="attr" name="layout_row" />
<public type="attr" name="layout_rowSpan" />
-
<public type="attr" name="layout_columnSpan" />
<public type="attr" name="layout_widthSpec" />
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index e5f52e2..dd0d064 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -6,7 +6,6 @@
android:label="@string/app_label"
android:process="system"
android:backupAgent="SettingsBackupAgent"
- android:fullBackupAgent="SettingsBackupAgent"
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_settings">
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9469601..3a7a6e1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -36,7 +36,7 @@ import java.util.zip.CRC32;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupAgentHelper;
-import android.app.backup.FullBackup;
+import android.app.backup.FullBackupDataOutput;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -132,58 +132,22 @@ public class SettingsBackupAgent extends BackupAgentHelper {
byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
byte[] wifiConfigData = getFileData(mWifiConfigFile);
- // This same agent class is used for both full and incremental backups. A full
- // backup is flagged by a 'null' oldState argument. In the case of a full backup,
- // the output is structured as tarfile contents.
- if (oldState != null) {
- long[] stateChecksums = readOldChecksums(oldState);
-
- stateChecksums[STATE_SYSTEM] =
- writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
- stateChecksums[STATE_SECURE] =
- writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
- stateChecksums[STATE_LOCALE] =
- writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
- stateChecksums[STATE_WIFI_SUPPLICANT] =
- writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
- wifiSupplicantData, data);
- stateChecksums[STATE_WIFI_CONFIG] =
- writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
- data);
-
- writeNewChecksums(stateChecksums, newState);
- } else {
- // Write the data to the staging file, then emit that as our tarfile
- // representation of the backed-up settings.
- String root = getFilesDir().getAbsolutePath();
- File stage = new File(root, STAGE_FILE);
- try {
- FileOutputStream filestream = new FileOutputStream(stage);
- BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
- DataOutputStream out = new DataOutputStream(bufstream);
-
- out.writeInt(FULL_BACKUP_VERSION);
-
- out.writeInt(systemSettingsData.length);
- out.write(systemSettingsData);
- out.writeInt(secureSettingsData.length);
- out.write(secureSettingsData);
- out.writeInt(locale.length);
- out.write(locale);
- out.writeInt(wifiSupplicantData.length);
- out.write(wifiSupplicantData);
- out.writeInt(wifiConfigData.length);
- out.write(wifiConfigData);
-
- out.flush(); // also flushes downstream
-
- // now we're set to emit the tar stream
- FullBackup.backupToTar(getPackageName(), FullBackup.DATA_TREE_TOKEN, null,
- root, stage.getAbsolutePath(), data);
- } finally {
- stage.delete();
- }
- }
+ long[] stateChecksums = readOldChecksums(oldState);
+
+ stateChecksums[STATE_SYSTEM] =
+ writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
+ stateChecksums[STATE_SECURE] =
+ writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+ stateChecksums[STATE_LOCALE] =
+ writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
+ stateChecksums[STATE_WIFI_SUPPLICANT] =
+ writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+ wifiSupplicantData, data);
+ stateChecksums[STATE_WIFI_CONFIG] =
+ writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+ data);
+
+ writeNewChecksums(stateChecksums, newState);
}
@Override
@@ -221,6 +185,45 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
@Override
+ public void onFullBackup(FullBackupDataOutput data) throws IOException {
+ byte[] systemSettingsData = getSystemSettings();
+ byte[] secureSettingsData = getSecureSettings();
+ byte[] locale = mSettingsHelper.getLocaleData();
+ byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
+ byte[] wifiConfigData = getFileData(mWifiConfigFile);
+
+ // Write the data to the staging file, then emit that as our tarfile
+ // representation of the backed-up settings.
+ String root = getFilesDir().getAbsolutePath();
+ File stage = new File(root, STAGE_FILE);
+ try {
+ FileOutputStream filestream = new FileOutputStream(stage);
+ BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
+ DataOutputStream out = new DataOutputStream(bufstream);
+
+ out.writeInt(FULL_BACKUP_VERSION);
+
+ out.writeInt(systemSettingsData.length);
+ out.write(systemSettingsData);
+ out.writeInt(secureSettingsData.length);
+ out.write(secureSettingsData);
+ out.writeInt(locale.length);
+ out.write(locale);
+ out.writeInt(wifiSupplicantData.length);
+ out.write(wifiSupplicantData);
+ out.writeInt(wifiConfigData.length);
+ out.write(wifiConfigData);
+
+ out.flush(); // also flushes downstream
+
+ // now we're set to emit the tar stream
+ fullBackupFile(stage, data);
+ } finally {
+ stage.delete();
+ }
+ }
+
+ @Override
public void onRestoreFile(ParcelFileDescriptor data, long size,
int type, String domain, String relpath, long mode, long mtime)
throws IOException {
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml
index 258059c..39c36f1 100644
--- a/packages/SharedStorageBackup/AndroidManifest.xml
+++ b/packages/SharedStorageBackup/AndroidManifest.xml
@@ -23,7 +23,7 @@
<application android:allowClearUserData="false"
android:permission="android.permission.CONFIRM_FULL_BACKUP"
- android:fullBackupAgent=".SharedStorageAgent"
+ android:backupAgent=".SharedStorageAgent"
android:allowBackup="false" >
</application>
</manifest>
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
index b02ca2e..6c677b8 100644
--- a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
@@ -1,9 +1,10 @@
package com.android.sharedstoragebackup;
-import android.app.backup.FullBackup;
import android.app.backup.FullBackupAgent;
+import android.app.backup.FullBackup;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackupDataOutput;
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
@@ -30,9 +31,11 @@ public class SharedStorageAgent extends FullBackupAgent {
}
}
+ /**
+ * Full backup of the shared-storage filesystem
+ */
@Override
- public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState) throws IOException {
+ public void onFullBackup(FullBackupDataOutput output) throws IOException {
// If there are shared-storage volumes available, run the inherited directory-
// hierarchy backup process on them. By convention in the Storage Manager, the
// "primary" shared storage volume is first in the list.
@@ -43,20 +46,12 @@ public class SharedStorageAgent extends FullBackupAgent {
// shared/N/path/to/file
// The restore will then extract to the given volume
String domain = FullBackup.SHARED_PREFIX + i;
- processTree(null, domain, v.getPath(), null, data);
+ fullBackupFileTree(null, domain, v.getPath(), null, output);
}
}
}
/**
- * Incremental onRestore() implementation is not used.
- */
- @Override
- public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
- throws IOException {
- }
-
- /**
* Full restore of one file to shared storage
*/
@Override
@@ -88,6 +83,6 @@ public class SharedStorageAgent extends FullBackupAgent {
Slog.e(TAG, "Skipping data with malformed path " + relpath);
}
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, false);
+ FullBackup.restoreFile(data, size, type, -1, mtime, outFile);
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 3aa1239..6afccec 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -23,6 +23,7 @@ import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IBackupAgent;
import android.app.PendingIntent;
+import android.app.backup.BackupAgent;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackup;
import android.app.backup.RestoreSet;
@@ -64,6 +65,7 @@ import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -1587,8 +1589,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Initiate the target's backup pass
prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
- agent.doBackup(savedState, backupData, newState, false,
- token, mBackupManagerBinder);
+ agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
boolean success = waitUntilOperationComplete(token);
if (!success) {
@@ -1764,30 +1765,31 @@ class BackupManagerService extends IBackupManager.Stub {
if (agent != null) {
try {
ApplicationInfo app = pkg.applicationInfo;
- boolean sendApk = mIncludeApks
+ final boolean sendApk = mIncludeApks
&& ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
sendOnBackupPackage(pkg.packageName);
- {
- BackupDataOutput output = new BackupDataOutput(
- mOutputFile.getFileDescriptor());
+ BackupDataOutput output = new BackupDataOutput(
+ mOutputFile.getFileDescriptor());
- if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
- writeAppManifest(pkg, mManifestFile, sendApk);
- FullBackup.backupToTar(pkg.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
+ writeAppManifest(pkg, mManifestFile, sendApk);
+ FullBackup.backupToTar(pkg.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+
+ if (sendApk) {
+ writeApkToBackup(pkg, output);
}
- if (DEBUG) Slog.d(TAG, "Calling doBackup()");
+ if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
final int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, sendApk,
- token, mBackupManagerBinder);
+ agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
} else {
@@ -1802,6 +1804,29 @@ class BackupManagerService extends IBackupManager.Stub {
tearDown(pkg);
}
+ private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
+ // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
+ final String appSourceDir = pkg.applicationInfo.sourceDir;
+ final String apkDir = new File(appSourceDir).getParent();
+ FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
+ apkDir, appSourceDir, output);
+
+ // Save associated .obb content if it exists and we did save the apk
+ // check for .obb and save those too
+ final File obbDir = Environment.getExternalStorageAppObbDirectory(pkg.packageName);
+ if (obbDir != null) {
+ if (DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
+ File[] obbFiles = obbDir.listFiles();
+ if (obbFiles != null) {
+ final String obbDirName = obbDir.getAbsolutePath();
+ for (File obb : obbFiles) {
+ FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
+ obbDirName, obb.getAbsolutePath(), output);
+ }
+ }
+ }
+ }
+
private void backupSharedStorage() throws RemoteException {
PackageInfo pkg = null;
try {
@@ -1813,7 +1838,7 @@ class BackupManagerService extends IBackupManager.Stub {
final int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, false, token, mBackupManagerBinder);
+ agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on shared storage");
} else {
@@ -1933,7 +1958,7 @@ class BackupManagerService extends IBackupManager.Stub {
static class FileMetadata {
String packageName; // name of the owning app
String installerPackageName; // name of the market-type app that installed the owner
- int type; // e.g. FullBackup.TYPE_DIRECTORY
+ int type; // e.g. BackupAgent.TYPE_DIRECTORY
String domain; // e.g. FullBackup.DATABASE_TREE_TOKEN
String path; // subpath within the semantic domain
long mode; // e.g. 0666 (actually int)
@@ -2182,15 +2207,15 @@ class BackupManagerService extends IBackupManager.Stub {
// If we haven't sent any data to this app yet, we probably
// need to clear it first. Check that.
if (!mClearedPackages.contains(pkg)) {
- // apps with their own full backup agents are
+ // apps with their own backup agents are
// responsible for coherently managing a full
// restore.
- if (mTargetApp.fullBackupAgentName == null) {
+ if (mTargetApp.backupAgentName == null) {
if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
clearApplicationDataSynchronous(pkg);
} else {
- if (DEBUG) Slog.d(TAG, "full backup agent ("
- + mTargetApp.fullBackupAgentName + ") => no clear");
+ if (DEBUG) Slog.d(TAG, "backup agent ("
+ + mTargetApp.backupAgentName + ") => no clear");
}
mClearedPackages.add(pkg);
} else {
@@ -2686,7 +2711,7 @@ class BackupManagerService extends IBackupManager.Stub {
StringBuilder b = new StringBuilder(128);
// mode string
- b.append((info.type == FullBackup.TYPE_DIRECTORY) ? 'd' : '-');
+ b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
b.append(((info.mode & 0400) != 0) ? 'r' : '-');
b.append(((info.mode & 0200) != 0) ? 'w' : '-');
b.append(((info.mode & 0100) != 0) ? 'x' : '-');
@@ -2746,9 +2771,9 @@ class BackupManagerService extends IBackupManager.Stub {
}
switch (typeChar) {
- case '0': info.type = FullBackup.TYPE_FILE; break;
+ case '0': info.type = BackupAgent.TYPE_FILE; break;
case '5': {
- info.type = FullBackup.TYPE_DIRECTORY;
+ info.type = BackupAgent.TYPE_DIRECTORY;
if (info.size != 0) {
Slog.w(TAG, "Directory entry with nonzero size in header");
info.size = 0;
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 08c6699..950f3b6 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -138,7 +138,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
if (outFile == null) {
Slog.w(TAG, "Skipping unrecognized system file: [ " + domain + " : " + path + " ]");
}
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
+ FullBackup.restoreFile(data, size, type, mode, mtime, outFile);
if (restoredWallpaper) {
WallpaperManagerService wallpaper =