138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate/* 238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * Copyright (C) 2011 The Android Open Source Project 338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * 438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * Licensed under the Apache License, Version 2.0 (the "License"); 538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * you may not use this file except in compliance with the License. 638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * You may obtain a copy of the License at 738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * 838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * http://www.apache.org/licenses/LICENSE-2.0 938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * 1038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * Unless required by applicable law or agreed to in writing, software 1138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * distributed under the License is distributed on an "AS IS" BASIS, 1238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * See the License for the specific language governing permissions and 1438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * limitations under the License. 1538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 1638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 1738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tatepackage com.android.hugebackup; 1838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 1938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport android.app.backup.BackupAgent; 2038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport android.app.backup.BackupDataInput; 2138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport android.app.backup.BackupDataOutput; 2238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport android.os.ParcelFileDescriptor; 2338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 2438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.ByteArrayInputStream; 2538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.ByteArrayOutputStream; 2638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.DataInputStream; 2738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.DataOutputStream; 2838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.File; 2938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.FileInputStream; 3038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.FileOutputStream; 3138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.IOException; 3238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tateimport java.io.RandomAccessFile; 3338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 3438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate/** 3538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * This is the backup/restore agent class for the BackupRestore sample 3638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * application. This particular agent illustrates using the backup and 3738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * restore APIs directly, without taking advantage of any helper classes. 3838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 3938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tatepublic class HugeAgent extends BackupAgent { 4038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** 4138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * We put a simple version number into the state files so that we can 4238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * tell properly how to read "old" versions if at some point we want 4338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * to change what data we back up and how we store the state blob. 4438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 4538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate static final int AGENT_VERSION = 1; 4638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 4738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** 4838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * Pick an arbitrary string to use as the "key" under which the 4938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * data is backed up. This key identifies different data records 5038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * within this one application's data set. Since we only maintain 5138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * one piece of data we don't need to distinguish, so we just pick 5238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * some arbitrary tag to use. 5338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 5438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate static final String APP_DATA_KEY = "alldata"; 5538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate static final String HUGE_DATA_KEY = "colossus"; 5638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 5738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** The app's current data, read from the live disk file */ 5838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate boolean mAddMayo; 5938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate boolean mAddTomato; 6038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate int mFilling; 6138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 6238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** The location of the application's persistent data file */ 6338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate File mDataFile; 6438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 6538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** For convenience, we set up the File object for the app's data on creation */ 6638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate @Override 6738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate public void onCreate() { 6838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mDataFile = new File(getFilesDir(), HugeBackupActivity.DATA_FILE_NAME); 6938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 7038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 7138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** 7238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * The set of data backed up by this application is very small: just 7338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * two booleans and an integer. With such a simple dataset, it's 7438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * easiest to simply store a copy of the backed-up data as the state 7538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * blob describing the last dataset backed up. The state file 7638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * contents can be anything; it is private to the agent class, and 7738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * is never stored off-device. 7838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * 7938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * <p>One thing that an application may wish to do is tag the state 8038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * blob contents with a version number. This is so that if the 8138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * application is upgraded, the next time it attempts to do a backup, 8238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * it can detect that the last backup operation was performed by an 8338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * older version of the agent, and might therefore require different 8438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * handling. 8538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 8638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate @Override 8738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 8838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate ParcelFileDescriptor newState) throws IOException { 8938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // First, get the current data from the application's file. This 9038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // may throw an IOException, but in that case something has gone 9138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // badly wrong with the app's data on disk, and we do not want 9238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // to back up garbage data. If we just let the exception go, the 9338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Backup Manager will handle it and simply skip the current 9438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // backup operation. 9538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate synchronized (HugeBackupActivity.sDataLock) { 9638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate RandomAccessFile file = new RandomAccessFile(mDataFile, "r"); 9738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mFilling = file.readInt(); 9838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mAddMayo = file.readBoolean(); 9938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mAddTomato = file.readBoolean(); 10038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 10138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 10238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // If the new state file descriptor is null, this is the first time 10338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // a backup is being performed, so we know we have to write the 10438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // data. If there <em>is</em> a previous state blob, we want to 10538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // double check whether the current data is actually different from 10638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // our last backup, so that we can avoid transmitting redundant 10738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // data to the storage backend. 10838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate boolean doBackup = (oldState == null); 10938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate if (!doBackup) { 11038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate doBackup = compareStateFile(oldState); 11138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 11238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 11338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // If we decided that we do in fact need to write our dataset, go 11438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // ahead and do that. The way this agent backs up the data is to 11538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // flatten it into a single buffer, then write that to the backup 11638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // transport under the single key string. 11738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate if (doBackup) { 11838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); 11938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 12038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // We use a DataOutputStream to write structured data into 12138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // the buffering stream 12238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate DataOutputStream outWriter = new DataOutputStream(bufStream); 12338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate outWriter.writeInt(mFilling); 12438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate outWriter.writeBoolean(mAddMayo); 12538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate outWriter.writeBoolean(mAddTomato); 12638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 12738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Okay, we've flattened the data for transmission. Pull it 12838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // out of the buffering stream object and send it off. 12938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate byte[] buffer = bufStream.toByteArray(); 13038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate int len = buffer.length; 13138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate data.writeEntityHeader(APP_DATA_KEY, len); 13238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate data.writeEntityData(buffer, len); 13338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 13438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // ***** pathological behavior ***** 13538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Now, in order to incur deliberate too-much-data failures, 13638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // try to back up 20 MB of data besides what we already pushed. 13738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate final int MEGABYTE = 1024*1024; 13838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate final int NUM_MEGS = 20; 13938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate buffer = new byte[MEGABYTE]; 14038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate data.writeEntityHeader(HUGE_DATA_KEY, NUM_MEGS * MEGABYTE); 14138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate for (int i = 0; i < NUM_MEGS; i++) { 14238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate data.writeEntityData(buffer, MEGABYTE); 14338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 14438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 14538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 14638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Finally, in all cases, we need to write the new state blob 14738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate writeStateFile(newState); 14838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 14938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 15038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** 15138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * Helper routine - read a previous state file and decide whether to 15238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * perform a backup based on its contents. 15338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * 15438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * @return <code>true</code> if the application's data has changed since 15538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * the last backup operation; <code>false</code> otherwise. 15638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 15738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate boolean compareStateFile(ParcelFileDescriptor oldState) { 15838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate FileInputStream instream = new FileInputStream(oldState.getFileDescriptor()); 15938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate DataInputStream in = new DataInputStream(instream); 16038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 16138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate try { 16238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate int stateVersion = in.readInt(); 16338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate if (stateVersion > AGENT_VERSION) { 16438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Whoops; the last version of the app that backed up 16538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // data on this device was <em>newer</em> than the current 16638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // version -- the user has downgraded. That's problematic. 16738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // In this implementation, we recover by simply rewriting 16838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // the backup. 16938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate return true; 17038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 17138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 17238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // The state data we store is just a mirror of the app's data; 17338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // read it from the state file then return 'true' if any of 17438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // it differs from the current data. 17538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate int lastFilling = in.readInt(); 17638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate boolean lastMayo = in.readBoolean(); 17738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate boolean lastTomato = in.readBoolean(); 17838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 17938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate return (lastFilling != mFilling) 18038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate || (lastTomato != mAddTomato) 18138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate || (lastMayo != mAddMayo); 18238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } catch (IOException e) { 18338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // If something went wrong reading the state file, be safe 18438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // and back up the data again. 18538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate return true; 18638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 18738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 18838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 18938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** 19038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * Write out the new state file: the version number, followed by the 19138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * three bits of data as we sent them off to the backup transport. 19238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 19338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate void writeStateFile(ParcelFileDescriptor stateFile) throws IOException { 19438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor()); 19538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate DataOutputStream out = new DataOutputStream(outstream); 19638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 19738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate out.writeInt(AGENT_VERSION); 19838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate out.writeInt(mFilling); 19938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate out.writeBoolean(mAddMayo); 20038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate out.writeBoolean(mAddTomato); 20138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 20238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 20338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate /** 20438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * This application does not do any "live" restores of its own data, 20538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * so the only time a restore will happen is when the application is 20638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * installed. This means that the activity itself is not going to 20738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * be running while we change its data out from under it. That, in 20838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * turn, means that there is no need to send out any sort of notification 20938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * of the new data: we only need to read the data from the stream 21038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * provided here, build the application's new data file, and then 21138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * write our new backup state blob that will be consulted at the next 21238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * backup operation. 21338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * 21438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * <p>We don't bother checking the versionCode of the app who originated 21538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * the data because we have never revised the backup data format. If 21638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * we had, the 'appVersionCode' parameter would tell us how we should 21738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate * interpret the data we're about to read. 21838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate */ 21938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate @Override 22038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate public void onRestore(BackupDataInput data, int appVersionCode, 22138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate ParcelFileDescriptor newState) throws IOException { 22238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // We should only see one entity in the data stream, but the safest 22338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // way to consume it is using a while() loop 22438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate while (data.readNextHeader()) { 22538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate String key = data.getKey(); 22638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate int dataSize = data.getDataSize(); 22738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 22838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate if (APP_DATA_KEY.equals(key)) { 22938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // It's our saved data, a flattened chunk of data all in 23038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // one buffer. Use some handy structured I/O classes to 23138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // extract it. 23238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate byte[] dataBuf = new byte[dataSize]; 23338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate data.readEntityData(dataBuf, 0, dataSize); 23438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); 23538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate DataInputStream in = new DataInputStream(baStream); 23638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 23738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mFilling = in.readInt(); 23838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mAddMayo = in.readBoolean(); 23938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate mAddTomato = in.readBoolean(); 24038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 24138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Now we are ready to construct the app's data file based 24238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // on the data we are restoring from. 24338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate synchronized (HugeBackupActivity.sDataLock) { 24438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate RandomAccessFile file = new RandomAccessFile(mDataFile, "rw"); 24538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate file.setLength(0L); 24638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate file.writeInt(mFilling); 24738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate file.writeBoolean(mAddMayo); 24838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate file.writeBoolean(mAddTomato); 24938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 25038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } else { 25138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // Curious! This entity is data under a key we do not 25238507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // understand how to process. Just skip it. 25338507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate data.skipEntityData(); 25438507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 25538507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 25638507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate 25738507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // The last thing to do is write the state blob that describes the 25838507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate // app's data as restored from backup. 25938507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate writeStateFile(newState); 26038507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate } 26138507bb993239a4d8135c6cc253187efe6e976fcChristopher Tate} 262