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
17package android.app.backup;
18
19import android.annotation.SystemApi;
20import android.app.backup.RestoreSession;
21import android.app.backup.IBackupManager;
22import android.app.backup.IRestoreSession;
23import android.content.Context;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.util.Log;
27
28/**
29 * The interface through which an application interacts with the Android backup service to
30 * request backup and restore operations.
31 * Applications instantiate it using the constructor and issue calls through that instance.
32 * <p>
33 * When an application has made changes to data which should be backed up, a
34 * call to {@link #dataChanged()} will notify the backup service. The system
35 * will then schedule a backup operation to occur in the near future. Repeated
36 * calls to {@link #dataChanged()} have no further effect until the backup
37 * operation actually occurs.
38 * <p>
39 * A backup or restore operation for your application begins when the system launches the
40 * {@link android.app.backup.BackupAgent} subclass you've declared in your manifest. See the
41 * documentation for {@link android.app.backup.BackupAgent} for a detailed description
42 * of how the operation then proceeds.
43 * <p>
44 * Several attributes affecting the operation of the backup and restore mechanism
45 * can be set on the <code>
46 * <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
47 * tag in your application's AndroidManifest.xml file.
48 *
49 * <div class="special reference">
50 * <h3>Developer Guides</h3>
51 * <p>For more information about using BackupManager, read the
52 * <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p></div>
53 *
54 * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
55 * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
56 * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
57 * @attr ref android.R.styleable#AndroidManifestApplication_restoreAnyVersion
58 */
59public class BackupManager {
60    private static final String TAG = "BackupManager";
61
62    private Context mContext;
63    private static IBackupManager sService;
64
65    private static void checkServiceBinder() {
66        if (sService == null) {
67            sService = IBackupManager.Stub.asInterface(
68                    ServiceManager.getService(Context.BACKUP_SERVICE));
69        }
70    }
71
72    /**
73     * Constructs a BackupManager object through which the application can
74     * communicate with the Android backup system.
75     *
76     * @param context The {@link android.content.Context} that was provided when
77     *                one of your application's {@link android.app.Activity Activities}
78     *                was created.
79     */
80    public BackupManager(Context context) {
81        mContext = context;
82    }
83
84    /**
85     * Notifies the Android backup system that your application wishes to back up
86     * new changes to its data.  A backup operation using your application's
87     * {@link android.app.backup.BackupAgent} subclass will be scheduled when you
88     * call this method.
89     */
90    public void dataChanged() {
91        checkServiceBinder();
92        if (sService != null) {
93            try {
94                sService.dataChanged(mContext.getPackageName());
95            } catch (RemoteException e) {
96                Log.d(TAG, "dataChanged() couldn't connect");
97            }
98        }
99    }
100
101    /**
102     * Convenience method for callers who need to indicate that some other package
103     * needs a backup pass.  This can be useful in the case of groups of packages
104     * that share a uid.
105     * <p>
106     * This method requires that the application hold the "android.permission.BACKUP"
107     * permission if the package named in the argument does not run under the same uid
108     * as the caller.
109     *
110     * @param packageName The package name identifying the application to back up.
111     */
112    public static void dataChanged(String packageName) {
113        checkServiceBinder();
114        if (sService != null) {
115            try {
116                sService.dataChanged(packageName);
117            } catch (RemoteException e) {
118                Log.e(TAG, "dataChanged(pkg) couldn't connect");
119            }
120        }
121    }
122
123    /**
124     * Restore the calling application from backup.  The data will be restored from the
125     * current backup dataset if the application has stored data there, or from
126     * the dataset used during the last full device setup operation if the current
127     * backup dataset has no matching data.  If no backup data exists for this application
128     * in either source, a nonzero value will be returned.
129     *
130     * <p>If this method returns zero (meaning success), the OS will attempt to retrieve
131     * a backed-up dataset from the remote transport, instantiate the application's
132     * backup agent, and pass the dataset to the agent's
133     * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
134     * method.
135     *
136     * @param observer The {@link RestoreObserver} to receive callbacks during the restore
137     * operation. This must not be null.
138     *
139     * @return Zero on success; nonzero on error.
140     */
141    public int requestRestore(RestoreObserver observer) {
142        int result = -1;
143        checkServiceBinder();
144        if (sService != null) {
145            RestoreSession session = null;
146            try {
147                IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
148                        null);
149                if (binder != null) {
150                    session = new RestoreSession(mContext, binder);
151                    result = session.restorePackage(mContext.getPackageName(), observer);
152                }
153            } catch (RemoteException e) {
154                Log.e(TAG, "restoreSelf() unable to contact service");
155            } finally {
156                if (session != null) {
157                    session.endRestoreSession();
158                }
159            }
160        }
161        return result;
162    }
163
164    // system APIs start here
165
166    /**
167     * Begin the process of restoring data from backup.  See the
168     * {@link android.app.backup.RestoreSession} class for documentation on that process.
169     * @hide
170     */
171    @SystemApi
172    public RestoreSession beginRestoreSession() {
173        RestoreSession session = null;
174        checkServiceBinder();
175        if (sService != null) {
176            try {
177                // All packages, current transport
178                IRestoreSession binder = sService.beginRestoreSession(null, null);
179                if (binder != null) {
180                    session = new RestoreSession(mContext, binder);
181                }
182            } catch (RemoteException e) {
183                Log.e(TAG, "beginRestoreSession() couldn't connect");
184            }
185        }
186        return session;
187    }
188
189    /**
190     * Enable/disable the backup service entirely.  When disabled, no backup
191     * or restore operations will take place.  Data-changed notifications will
192     * still be observed and collected, however, so that changes made while the
193     * mechanism was disabled will still be backed up properly if it is enabled
194     * at some point in the future.
195     *
196     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
197     *
198     * @hide
199     */
200    @SystemApi
201    public void setBackupEnabled(boolean isEnabled) {
202        checkServiceBinder();
203        if (sService != null) {
204            try {
205                sService.setBackupEnabled(isEnabled);
206            } catch (RemoteException e) {
207                Log.e(TAG, "setBackupEnabled() couldn't connect");
208            }
209        }
210    }
211
212    /**
213     * Report whether the backup mechanism is currently enabled.
214     *
215     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
216     *
217     * @hide
218     */
219    @SystemApi
220    public boolean isBackupEnabled() {
221        checkServiceBinder();
222        if (sService != null) {
223            try {
224                return sService.isBackupEnabled();
225            } catch (RemoteException e) {
226                Log.e(TAG, "isBackupEnabled() couldn't connect");
227            }
228        }
229        return false;
230    }
231
232    /**
233     * Enable/disable data restore at application install time.  When enabled, app
234     * installation will include an attempt to fetch the app's historical data from
235     * the archival restore dataset (if any).  When disabled, no such attempt will
236     * be made.
237     *
238     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
239     *
240     * @hide
241     */
242    @SystemApi
243    public void setAutoRestore(boolean isEnabled) {
244        checkServiceBinder();
245        if (sService != null) {
246            try {
247                sService.setAutoRestore(isEnabled);
248            } catch (RemoteException e) {
249                Log.e(TAG, "setAutoRestore() couldn't connect");
250            }
251        }
252    }
253
254    /**
255     * Identify the currently selected transport.  Callers must hold the
256     * android.permission.BACKUP permission to use this method.
257     * @return The name of the currently active backup transport.  In case of
258     *   failure or if no transport is currently active, this method returns {@code null}.
259     *
260     * @hide
261     */
262    @SystemApi
263    public String getCurrentTransport() {
264        checkServiceBinder();
265        if (sService != null) {
266            try {
267                return sService.getCurrentTransport();
268            } catch (RemoteException e) {
269                Log.e(TAG, "getCurrentTransport() couldn't connect");
270            }
271        }
272        return null;
273    }
274
275    /**
276     * Request a list of all available backup transports' names.  Callers must
277     * hold the android.permission.BACKUP permission to use this method.
278     *
279     * @hide
280     */
281    @SystemApi
282    public String[] listAllTransports() {
283        checkServiceBinder();
284        if (sService != null) {
285            try {
286                return sService.listAllTransports();
287            } catch (RemoteException e) {
288                Log.e(TAG, "listAllTransports() couldn't connect");
289            }
290        }
291        return null;
292    }
293
294    /**
295     * Specify the current backup transport.  Callers must hold the
296     * android.permission.BACKUP permission to use this method.
297     *
298     * @param transport The name of the transport to select.  This should be one
299     *   of the names returned by {@link #listAllTransports()}.
300     * @return The name of the previously selected transport.  If the given transport
301     *   name is not one of the currently available transports, no change is made to
302     *   the current transport setting and the method returns null.
303     *
304     * @hide
305     */
306    @SystemApi
307    public String selectBackupTransport(String transport) {
308        checkServiceBinder();
309        if (sService != null) {
310            try {
311                return sService.selectBackupTransport(transport);
312            } catch (RemoteException e) {
313                Log.e(TAG, "selectBackupTransport() couldn't connect");
314            }
315        }
316        return null;
317    }
318
319    /**
320     * Schedule an immediate backup attempt for all pending key/value updates.  This
321     * is primarily intended for transports to use when they detect a suitable
322     * opportunity for doing a backup pass.  If there are no pending updates to
323     * be sent, no action will be taken.  Even if some updates are pending, the
324     * transport will still be asked to confirm via the usual requestBackupTime()
325     * method.
326     *
327     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
328     *
329     * @hide
330     */
331    @SystemApi
332    public void backupNow() {
333        checkServiceBinder();
334        if (sService != null) {
335            try {
336                sService.backupNow();
337            } catch (RemoteException e) {
338                Log.e(TAG, "backupNow() couldn't connect");
339            }
340        }
341    }
342}
343