diff options
author | Christopher Tate <ctate@google.com> | 2009-07-07 13:11:41 -0700 |
---|---|---|
committer | Christopher Tate <ctate@android.com> | 2009-07-10 11:19:16 -0700 |
commit | de6f131625bc4a24170d021e49d61fb694138669 (patch) | |
tree | f8cdf31756e467d6953391d134eb42836f887ce0 /src/com/android/browser/BrowserBackupAgent.java | |
parent | 4524cc71312ba78e5b7430f347da45c0a3d3a74d (diff) | |
download | android_packages_apps_Gello-de6f131625bc4a24170d021e49d61fb694138669.tar.gz android_packages_apps_Gello-de6f131625bc4a24170d021e49d61fb694138669.tar.bz2 android_packages_apps_Gello-de6f131625bc4a24170d021e49d61fb694138669.zip |
Skeleton backup agent for Browser
This is a skeleton backup agent for the Android Browser, intended to back up and
restore the bookmarks table from browser.db by extracting the bookmarks table
into a flattened file representation on backup, then unflattening and rebuilding
the table during restore.
It compiles but is completely untested, since the db code to read/write the
bookmarks table is not finished. The backup agent has been declared in the
Browser manifest, however.
Diffstat (limited to 'src/com/android/browser/BrowserBackupAgent.java')
-rw-r--r-- | src/com/android/browser/BrowserBackupAgent.java | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/com/android/browser/BrowserBackupAgent.java b/src/com/android/browser/BrowserBackupAgent.java new file mode 100644 index 00000000..e38ef054 --- /dev/null +++ b/src/com/android/browser/BrowserBackupAgent.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.browser; + +import java.io.IOException; + +import android.app.BackupAgent; +import android.backup.BackupDataInput; +import android.backup.BackupDataOutput; +import android.database.Cursor; +import android.os.ParcelFileDescriptor; +import android.provider.Browser; +import android.provider.Browser.BookmarkColumns; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +import java.util.zip.CRC32; + +/** + * Settings backup agent for the Android browser. Currently the only thing + * stored is the set of bookmarks. It's okay if I/O exceptions are thrown + * out of the agent; the calling code handles it and the backup operation + * simply fails. + */ +public class BrowserBackupAgent extends BackupAgent { + static final String BOOKMARK_KEY = "_bookmarks_"; + + /** + * In order to determine whether the bookmark set has changed since the + * last time we did a backup, we store the following bits of info in the + * state file after a backup: + * + * 1. the size of the flattened bookmark file + * 2. the CRC32 of that file + * + * After we flatten the bookmarks file here in onBackup, we compare its + * metrics with the values from the saved state. If they match, it means + * the bookmarks didn't really change and we don't need to send the data. + * (If they don't match, of course, then they've changed and we do indeed + * send the new flattened file to be backed up.) + */ + @Override + public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) throws IOException { + long savedFileSize = -1; + long savedCrc = -1; + + // Extract the previous bookmark file size & CRC from the saved state + DataInputStream in = new DataInputStream( + new FileInputStream(oldState.getFileDescriptor())); + try { + savedFileSize = in.readLong(); + savedCrc = in.readLong(); + } catch (EOFException e) { + // It means we had no previous state; that's fine + } + + // TODO: BUILD THE FLATTENED BOOKMARK FILE FROM THE DB (into tmpfile) + File tmpfile = getFilesDir().createTempFile("bkp", null); + CRC32 crc = new CRC32(); + try { + Cursor cursor = getContentResolver().query(Browser.BOOKMARKS_URI, + new String[] { BookmarkColumns.URL, BookmarkColumns.VISITS, + BookmarkColumns.DATE, BookmarkColumns.CREATED, + BookmarkColumns.TITLE }, + BookmarkColumns.BOOKMARK + " == 1 ", null, null); + int count = cursor.getCount(); + FileOutputStream out = new FileOutputStream(tmpfile); + for (int i = 0; i < count; i++) { + StringBuilder sb = new StringBuilder(); + // URL + sb.append("'"); + sb.append(cursor.getString(0)); + sb.append("','"); + // VISITS + sb.append(cursor.getInt(1)); + sb.append("','"); + // DATE + sb.append(cursor.getLong(2)); + sb.append("','"); + // CREATED + sb.append(cursor.getLong(3)); + sb.append("','"); + // TITLE + sb.append(cursor.getString(4)); + sb.append("'"); + out.write(sb.toString().getBytes()); + } + out.close(); + /* + android.util.Log.d("s", "backing up data" + + getContentResolver().openFileDescriptor(Browser.BOOKMARKS_URI, "r").toString()); + */ + // NOTE: feed the flattened data through the crc engine on the fly + // to save re-reading it later just to checksum it + + // Once the file is built, compare its metrics with the saved ones + if ((crc.getValue() != savedCrc) || (tmpfile.length() != savedFileSize)) { + // Different checksum or different size, so we need to back it up + copyFileToBackup(BOOKMARK_KEY, tmpfile, data); + } + + // Last, record the metrics of the bookmark file that we just stored + writeBackupState(tmpfile.length(), crc.getValue(), newState); + } finally { + // Make sure to tidy up when we're done + tmpfile.delete(); + } + } + + /** + * Restore from backup -- reads in the flattened bookmark file as supplied from + * the backup service, parses that out, and rebuilds the bookmarks table in the + * browser database from it. + */ + @Override + public void onRestore(BackupDataInput data, int appVersionCode, + ParcelFileDescriptor newState) throws IOException { + long crc = -1; + File tmpfile = getFilesDir().createTempFile("rst", null); + try { + while (data.readNextHeader()) { + if (BOOKMARK_KEY.equals(data.getKey())) { + // Read the flattened bookmark data into a temp file + crc = copyBackupToFile(data, tmpfile, data.getDataSize()); + + // TODO: READ THE FLAT BOOKMARKS FILE 'tmpfile' AND REBUILD THE DB TABLE + } + + // Last, write the state we just restored from so we can discern + // changes whenever we get invoked for backup in the future + writeBackupState(tmpfile.length(), crc, newState); + } + } finally { + // Whatever happens, delete the temp file + tmpfile.delete(); + } + } + + /* + * Utility functions + */ + + // Write the file to backup as a single record under the given key + private void copyFileToBackup(String key, File file, BackupDataOutput data) + throws IOException { + final int CHUNK = 8192; + byte[] buf = new byte[CHUNK]; + + int toCopy = (int) file.length(); + data.writeEntityHeader(key, toCopy); + + FileInputStream in = new FileInputStream(file); + int nRead; + while (toCopy > 0) { + nRead = in.read(buf, 0, CHUNK); + data.writeEntityData(buf, nRead); + toCopy -= nRead; + } + in.close(); + } + + // Read the given file from backup to a file, calculating a CRC32 along the way + private long copyBackupToFile(BackupDataInput data, File file, int toRead) + throws IOException { + final int CHUNK = 8192; + byte[] buf = new byte[CHUNK]; + CRC32 crc = new CRC32(); + + while (toRead > 0) { + int numRead = data.readEntityData(buf, 0, CHUNK); + crc.update(buf, 0, numRead); + toRead -= numRead; + } + + return crc.getValue(); + } + + // Write the given metrics to the new state file + private void writeBackupState(long fileSize, long crc, ParcelFileDescriptor stateFile) + throws IOException { + DataOutputStream out = new DataOutputStream( + new FileOutputStream(stateFile.getFileDescriptor())); + out.writeLong(fileSize); + out.writeLong(crc); + } +} |