• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.backup;
18 
19 import android.os.ParcelFileDescriptor;
20 import android.util.Log;
21 
22 import java.io.FileDescriptor;
23 import java.io.IOException;
24 import java.util.Map;
25 import java.util.TreeMap;
26 
27 /** @hide */
28 public class BackupHelperDispatcher {
29     private static final String TAG = "BackupHelperDispatcher";
30 
31     private static class Header {
32         int chunkSize; // not including the header
33         String keyPrefix;
34     }
35 
36     TreeMap<String,BackupHelper> mHelpers = new TreeMap<String,BackupHelper>();
37 
BackupHelperDispatcher()38     public BackupHelperDispatcher() {
39     }
40 
addHelper(String keyPrefix, BackupHelper helper)41     public void addHelper(String keyPrefix, BackupHelper helper) {
42         mHelpers.put(keyPrefix, helper);
43     }
44 
performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)45     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
46              ParcelFileDescriptor newState) throws IOException {
47         // First, do the helpers that we've already done, since they're already in the state
48         // file.
49         int err;
50         Header header = new Header();
51         TreeMap<String,BackupHelper> helpers = (TreeMap<String,BackupHelper>)mHelpers.clone();
52         FileDescriptor oldStateFD = null;
53         FileDescriptor newStateFD = newState.getFileDescriptor();
54 
55         if (oldState != null) {
56             oldStateFD = oldState.getFileDescriptor();
57             while ((err = readHeader_native(header, oldStateFD)) >= 0) {
58                 if (err == 0) {
59                     BackupHelper helper = helpers.get(header.keyPrefix);
60                     Log.d(TAG, "handling existing helper '" + header.keyPrefix + "' " + helper);
61                     if (helper != null) {
62                         doOneBackup(oldState, data, newState, header, helper);
63                         helpers.remove(header.keyPrefix);
64                     } else {
65                         skipChunk_native(oldStateFD, header.chunkSize);
66                     }
67                 }
68             }
69         }
70 
71         // Then go through and do the rest that we haven't done.
72         for (Map.Entry<String,BackupHelper> entry: helpers.entrySet()) {
73             header.keyPrefix = entry.getKey();
74             Log.d(TAG, "handling new helper '" + header.keyPrefix + "'");
75             BackupHelper helper = entry.getValue();
76             doOneBackup(oldState, data, newState, header, helper);
77         }
78     }
79 
doOneBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState, Header header, BackupHelper helper)80     private void doOneBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
81             ParcelFileDescriptor newState, Header header, BackupHelper helper)
82             throws IOException {
83         int err;
84         FileDescriptor newStateFD = newState.getFileDescriptor();
85 
86         // allocate space for the header in the file
87         int pos = allocateHeader_native(header, newStateFD);
88         if (pos < 0) {
89             throw new IOException("allocateHeader_native failed (error " + pos + ")");
90         }
91 
92         data.setKeyPrefix(header.keyPrefix);
93 
94         // do the backup
95         helper.performBackup(oldState, data, newState);
96 
97         // fill in the header (seeking back to pos).  The file pointer will be returned to
98         // where it was at the end of performBackup.  Header.chunkSize will not be filled in.
99         err = writeHeader_native(header, newStateFD, pos);
100         if (err != 0) {
101             throw new IOException("writeHeader_native failed (error " + err + ")");
102         }
103     }
104 
performRestore(BackupDataInput input, int appVersionCode, ParcelFileDescriptor newState)105     public void performRestore(BackupDataInput input, int appVersionCode,
106             ParcelFileDescriptor newState)
107             throws IOException {
108         boolean alreadyComplained = false;
109 
110         BackupDataInputStream stream = new BackupDataInputStream(input);
111         while (input.readNextHeader()) {
112 
113             String rawKey = input.getKey();
114             int pos = rawKey.indexOf(':');
115             if (pos > 0) {
116                 String prefix = rawKey.substring(0, pos);
117                 BackupHelper helper = mHelpers.get(prefix);
118                 if (helper != null) {
119                     stream.dataSize = input.getDataSize();
120                     stream.key = rawKey.substring(pos+1);
121                     helper.restoreEntity(stream);
122                 } else {
123                     if (!alreadyComplained) {
124                         Log.w(TAG, "Couldn't find helper for: '" + rawKey + "'");
125                         alreadyComplained = true;
126                     }
127                 }
128             } else {
129                 if (!alreadyComplained) {
130                     Log.w(TAG, "Entity with no prefix: '" + rawKey + "'");
131                     alreadyComplained = true;
132                 }
133             }
134             input.skipEntityData(); // In case they didn't consume the data.
135         }
136 
137         // Write out the state files -- mHelpers is a TreeMap, so the order is well defined.
138         for (BackupHelper helper: mHelpers.values()) {
139             helper.writeNewStateDescription(newState);
140         }
141     }
142 
readHeader_native(Header h, FileDescriptor fd)143     private static native int readHeader_native(Header h, FileDescriptor fd);
skipChunk_native(FileDescriptor fd, int bytesToSkip)144     private static native int skipChunk_native(FileDescriptor fd, int bytesToSkip);
145 
allocateHeader_native(Header h, FileDescriptor fd)146     private static native int allocateHeader_native(Header h, FileDescriptor fd);
writeHeader_native(Header h, FileDescriptor fd, int pos)147     private static native int writeHeader_native(Header h, FileDescriptor fd, int pos);
148 }
149 
150