diff --git a/api/current.txt b/api/current.txt index d009a64f355c1..d7e3cb30e8ac8 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 1ec7a964e5cda..eee14fb1a5b3b 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 8af78fadfc449..087f83c396dd1 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); /** @@ -80,6 +79,25 @@ oneway interface IBackupAgent { void doRestore(in ParcelFileDescriptor data, int appVersionCode, 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 diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 63f325870f91e..65c73f9b5eb89 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; /** - * @hide + * The default implementation backs up the entirety of the application's "owned" + * file system trees to the output. */ - public void onRestoreFile(ParcelFileDescriptor data, long size, - int type, String domain, String path, long mode, long mtime) - throws IOException { - // empty stub implementation + 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 filterSet = new HashSet(); + 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); } /** - * Package-private, used only for dispatching an extra step during full backup + * 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. */ - void onSaveApk(BackupDataOutput data) { + 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 excludes, FullBackupDataOutput output) { + File rootFile = new File(rootPath); + if (rootFile.exists()) { + LinkedList scanQueue = new LinkedList(); + 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. + *

+ * The file descriptor can only be read for {@code size} bytes; attempting to read + * more data has undefined behavior. + *

+ * 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, + File destination, int type, long mode, long mtime) + throws IOException { + FullBackup.restoreFile(data, size, type, mode, mtime, destination); + } + + /** + * Only specialized platform agents should overload this entry point to support + * restores to crazy non-app locations. + * @hide + */ + 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) { @@ -272,6 +516,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, diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index 3b70e19ad2442..d7f1c9f0fab41 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. + *

+ * 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 df1c3639bc587..faea76aee148d 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/<package>/... 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 filterSet = new HashSet(); - 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 excludes, BackupDataOutput data) { - File rootFile = new File(rootPath); - if (rootFile.exists()) { - LinkedList scanQueue = new LinkedList(); - 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 0000000000000..99dab1f760189 --- /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 454cb31953164..ddb6ef0d2f53d 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -90,15 +90,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 208869b6c2fdb..53d6bb17a5512 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 1a320608efae6..49eaf19126175 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"> The default value of this attribute is false. --> - - - @@ -800,7 +793,6 @@ -