15f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato/* 25f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * Copyright (C) 2009 The Android Open Source Project 35f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * 45f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * Licensed under the Apache License, Version 2.0 (the "License"); 55f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * you may not use this file except in compliance with the License. 65f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * You may obtain a copy of the License at 75f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * 85f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * http://www.apache.org/licenses/LICENSE-2.0 95f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * 105f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * Unless required by applicable law or agreed to in writing, software 115f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * distributed under the License is distributed on an "AS IS" BASIS, 125f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * See the License for the specific language governing permissions and 145f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato * limitations under the License. 155f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato */ 165f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 174528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tatepackage android.app.backup; 185f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 19d2d9ceb7305d593c1b767bbb05de0082a9af4109Joe Onoratoimport android.os.ParcelFileDescriptor; 2083248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onoratoimport android.util.Log; 2183248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato 224ababd922eac5931e0222862ff082dc29e012816Joe Onoratoimport java.io.FileDescriptor; 235a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Rootimport java.io.IOException; 24d2d9ceb7305d593c1b767bbb05de0082a9af4109Joe Onoratoimport java.util.Map; 255a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Rootimport java.util.TreeMap; 265f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 275f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato/** @hide */ 2806290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onoratopublic class BackupHelperDispatcher { 2906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato private static final String TAG = "BackupHelperDispatcher"; 3083248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato 314ababd922eac5931e0222862ff082dc29e012816Joe Onorato private static class Header { 324ababd922eac5931e0222862ff082dc29e012816Joe Onorato int chunkSize; // not including the header 334ababd922eac5931e0222862ff082dc29e012816Joe Onorato String keyPrefix; 344ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 354ababd922eac5931e0222862ff082dc29e012816Joe Onorato 3606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato TreeMap<String,BackupHelper> mHelpers = new TreeMap<String,BackupHelper>(); 3706290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato 3806290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato public BackupHelperDispatcher() { 3906290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato } 405f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 4106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato public void addHelper(String keyPrefix, BackupHelper helper) { 425f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato mHelpers.put(keyPrefix, helper); 435f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 445f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato 4506290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 464ababd922eac5931e0222862ff082dc29e012816Joe Onorato ParcelFileDescriptor newState) throws IOException { 474ababd922eac5931e0222862ff082dc29e012816Joe Onorato // First, do the helpers that we've already done, since they're already in the state 484ababd922eac5931e0222862ff082dc29e012816Joe Onorato // file. 494ababd922eac5931e0222862ff082dc29e012816Joe Onorato int err; 504ababd922eac5931e0222862ff082dc29e012816Joe Onorato Header header = new Header(); 514ababd922eac5931e0222862ff082dc29e012816Joe Onorato TreeMap<String,BackupHelper> helpers = (TreeMap<String,BackupHelper>)mHelpers.clone(); 524ababd922eac5931e0222862ff082dc29e012816Joe Onorato FileDescriptor oldStateFD = null; 534ababd922eac5931e0222862ff082dc29e012816Joe Onorato 544ababd922eac5931e0222862ff082dc29e012816Joe Onorato if (oldState != null) { 554ababd922eac5931e0222862ff082dc29e012816Joe Onorato oldStateFD = oldState.getFileDescriptor(); 564ababd922eac5931e0222862ff082dc29e012816Joe Onorato while ((err = readHeader_native(header, oldStateFD)) >= 0) { 574ababd922eac5931e0222862ff082dc29e012816Joe Onorato if (err == 0) { 584ababd922eac5931e0222862ff082dc29e012816Joe Onorato BackupHelper helper = helpers.get(header.keyPrefix); 594ababd922eac5931e0222862ff082dc29e012816Joe Onorato Log.d(TAG, "handling existing helper '" + header.keyPrefix + "' " + helper); 604ababd922eac5931e0222862ff082dc29e012816Joe Onorato if (helper != null) { 614ababd922eac5931e0222862ff082dc29e012816Joe Onorato doOneBackup(oldState, data, newState, header, helper); 624ababd922eac5931e0222862ff082dc29e012816Joe Onorato helpers.remove(header.keyPrefix); 634ababd922eac5931e0222862ff082dc29e012816Joe Onorato } else { 644ababd922eac5931e0222862ff082dc29e012816Joe Onorato skipChunk_native(oldStateFD, header.chunkSize); 654ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 664ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 674ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 684ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 694ababd922eac5931e0222862ff082dc29e012816Joe Onorato 704ababd922eac5931e0222862ff082dc29e012816Joe Onorato // Then go through and do the rest that we haven't done. 714ababd922eac5931e0222862ff082dc29e012816Joe Onorato for (Map.Entry<String,BackupHelper> entry: helpers.entrySet()) { 724ababd922eac5931e0222862ff082dc29e012816Joe Onorato header.keyPrefix = entry.getKey(); 734ababd922eac5931e0222862ff082dc29e012816Joe Onorato Log.d(TAG, "handling new helper '" + header.keyPrefix + "'"); 744ababd922eac5931e0222862ff082dc29e012816Joe Onorato BackupHelper helper = entry.getValue(); 754ababd922eac5931e0222862ff082dc29e012816Joe Onorato doOneBackup(oldState, data, newState, header, helper); 764ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 774ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 784ababd922eac5931e0222862ff082dc29e012816Joe Onorato 794ababd922eac5931e0222862ff082dc29e012816Joe Onorato private void doOneBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 804ababd922eac5931e0222862ff082dc29e012816Joe Onorato ParcelFileDescriptor newState, Header header, BackupHelper helper) 814ababd922eac5931e0222862ff082dc29e012816Joe Onorato throws IOException { 824ababd922eac5931e0222862ff082dc29e012816Joe Onorato int err; 834ababd922eac5931e0222862ff082dc29e012816Joe Onorato FileDescriptor newStateFD = newState.getFileDescriptor(); 844ababd922eac5931e0222862ff082dc29e012816Joe Onorato 854ababd922eac5931e0222862ff082dc29e012816Joe Onorato // allocate space for the header in the file 864ababd922eac5931e0222862ff082dc29e012816Joe Onorato int pos = allocateHeader_native(header, newStateFD); 874ababd922eac5931e0222862ff082dc29e012816Joe Onorato if (pos < 0) { 884ababd922eac5931e0222862ff082dc29e012816Joe Onorato throw new IOException("allocateHeader_native failed (error " + pos + ")"); 894ababd922eac5931e0222862ff082dc29e012816Joe Onorato } 904ababd922eac5931e0222862ff082dc29e012816Joe Onorato 914ababd922eac5931e0222862ff082dc29e012816Joe Onorato data.setKeyPrefix(header.keyPrefix); 924ababd922eac5931e0222862ff082dc29e012816Joe Onorato 934ababd922eac5931e0222862ff082dc29e012816Joe Onorato // do the backup 944ababd922eac5931e0222862ff082dc29e012816Joe Onorato helper.performBackup(oldState, data, newState); 954ababd922eac5931e0222862ff082dc29e012816Joe Onorato 964ababd922eac5931e0222862ff082dc29e012816Joe Onorato // fill in the header (seeking back to pos). The file pointer will be returned to 974ababd922eac5931e0222862ff082dc29e012816Joe Onorato // where it was at the end of performBackup. Header.chunkSize will not be filled in. 984ababd922eac5931e0222862ff082dc29e012816Joe Onorato err = writeHeader_native(header, newStateFD, pos); 994ababd922eac5931e0222862ff082dc29e012816Joe Onorato if (err != 0) { 1004ababd922eac5931e0222862ff082dc29e012816Joe Onorato throw new IOException("writeHeader_native failed (error " + err + ")"); 10106290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato } 10206290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato } 10306290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato 1045cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate public void performRestore(BackupDataInput input, int appVersionCode, 1055cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate ParcelFileDescriptor newState) 10606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato throws IOException { 10783248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato boolean alreadyComplained = false; 10883248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato 1095f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato BackupDataInputStream stream = new BackupDataInputStream(input); 1105f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato while (input.readNextHeader()) { 11183248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato 1125f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato String rawKey = input.getKey(); 1135f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato int pos = rawKey.indexOf(':'); 1145f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato if (pos > 0) { 1155f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato String prefix = rawKey.substring(0, pos); 11606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato BackupHelper helper = mHelpers.get(prefix); 1175f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato if (helper != null) { 1185f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato stream.dataSize = input.getDataSize(); 1195f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato stream.key = rawKey.substring(pos+1); 120efd0fab04b96d7ab0c1d8bf3b79397c8621e31c5Joe Onorato helper.restoreEntity(stream); 12183248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato } else { 12283248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato if (!alreadyComplained) { 12383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato Log.w(TAG, "Couldn't find helper for: '" + rawKey + "'"); 12483248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato alreadyComplained = true; 12583248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato } 12683248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato } 12783248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato } else { 12883248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato if (!alreadyComplained) { 12983248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato Log.w(TAG, "Entity with no prefix: '" + rawKey + "'"); 13083248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato alreadyComplained = true; 1315f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1325f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1335f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato input.skipEntityData(); // In case they didn't consume the data. 1345f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 135d2d9ceb7305d593c1b767bbb05de0082a9af4109Joe Onorato 13606290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato // Write out the state files -- mHelpers is a TreeMap, so the order is well defined. 13706290a4bb9b280fa14a2bbeb2d3ceb09396a78c3Joe Onorato for (BackupHelper helper: mHelpers.values()) { 138e28290e21f908b4e917099ff2aa41e3aab9310c2Christopher Tate helper.writeNewStateDescription(newState); 139d2d9ceb7305d593c1b767bbb05de0082a9af4109Joe Onorato } 1405f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato } 1414ababd922eac5931e0222862ff082dc29e012816Joe Onorato 1424ababd922eac5931e0222862ff082dc29e012816Joe Onorato private static native int readHeader_native(Header h, FileDescriptor fd); 1434ababd922eac5931e0222862ff082dc29e012816Joe Onorato private static native int skipChunk_native(FileDescriptor fd, int bytesToSkip); 1444ababd922eac5931e0222862ff082dc29e012816Joe Onorato 1454ababd922eac5931e0222862ff082dc29e012816Joe Onorato private static native int allocateHeader_native(Header h, FileDescriptor fd); 1464ababd922eac5931e0222862ff082dc29e012816Joe Onorato private static native int writeHeader_native(Header h, FileDescriptor fd, int pos); 1475f15d151b5101fadfe6cba1e8f4aa6367e8c603eJoe Onorato} 148d2d9ceb7305d593c1b767bbb05de0082a9af4109Joe Onorato 149