blob: ab2413d5d6f3ca44c4e62b570efcbfdcb2d2c296 [file] [log] [blame]
Christopher Tate487529a2009-04-29 14:03:25 -07001/*
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 com.android.server;
18
Jason parks1125d782011-01-12 09:47:26 -060019import com.android.internal.backup.BackupConstants;
20import com.android.internal.backup.IBackupTransport;
21import com.android.internal.backup.LocalTransport;
22import com.android.server.PackageManagerBackupAgent.Metadata;
23
Christopher Tate181fafa2009-05-14 11:12:14 -070024import android.app.ActivityManagerNative;
Christopher Tateb6787f22009-07-02 17:40:45 -070025import android.app.AlarmManager;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070026import android.app.AppGlobals;
Christopher Tate181fafa2009-05-14 11:12:14 -070027import android.app.IActivityManager;
28import android.app.IApplicationThread;
29import android.app.IBackupAgent;
Christopher Tateb6787f22009-07-02 17:40:45 -070030import android.app.PendingIntent;
Christopher Tate45281862010-03-05 15:46:30 -080031import android.app.backup.IBackupManager;
32import android.app.backup.IRestoreObserver;
33import android.app.backup.IRestoreSession;
Jason parks1125d782011-01-12 09:47:26 -060034import android.app.backup.RestoreSet;
Christopher Tate3799bc22009-05-06 16:13:56 -070035import android.content.BroadcastReceiver;
Dan Egnor87a02bc2009-06-17 02:30:10 -070036import android.content.ComponentName;
Christopher Tate487529a2009-04-29 14:03:25 -070037import android.content.Context;
38import android.content.Intent;
Christopher Tate3799bc22009-05-06 16:13:56 -070039import android.content.IntentFilter;
Dan Egnor87a02bc2009-06-17 02:30:10 -070040import android.content.ServiceConnection;
Christopher Tate181fafa2009-05-14 11:12:14 -070041import android.content.pm.ApplicationInfo;
Christopher Tatec7b31e32009-06-10 15:49:30 -070042import android.content.pm.IPackageDataObserver;
Christopher Tate1bb69062010-02-19 17:02:12 -080043import android.content.pm.IPackageManager;
Christopher Tate7b881282009-06-07 13:52:37 -070044import android.content.pm.PackageInfo;
Dan Egnor87a02bc2009-06-17 02:30:10 -070045import android.content.pm.PackageManager;
Oscar Montemayora8529f62009-11-18 10:14:20 -080046import android.content.pm.PackageManager.NameNotFoundException;
Jason parks1125d782011-01-12 09:47:26 -060047import android.content.pm.Signature;
Christopher Tate3799bc22009-05-06 16:13:56 -070048import android.net.Uri;
Christopher Tate487529a2009-04-29 14:03:25 -070049import android.os.Binder;
Christopher Tate3799bc22009-05-06 16:13:56 -070050import android.os.Bundle;
Christopher Tate22b87872009-05-04 16:41:53 -070051import android.os.Environment;
Christopher Tate487529a2009-04-29 14:03:25 -070052import android.os.Handler;
Christopher Tate44a27902010-01-27 17:15:49 -080053import android.os.HandlerThread;
Christopher Tate487529a2009-04-29 14:03:25 -070054import android.os.IBinder;
Christopher Tate44a27902010-01-27 17:15:49 -080055import android.os.Looper;
Christopher Tate487529a2009-04-29 14:03:25 -070056import android.os.Message;
Christopher Tate22b87872009-05-04 16:41:53 -070057import android.os.ParcelFileDescriptor;
Christopher Tateb6787f22009-07-02 17:40:45 -070058import android.os.PowerManager;
Christopher Tate043dadc2009-06-02 16:11:00 -070059import android.os.Process;
Christopher Tate487529a2009-04-29 14:03:25 -070060import android.os.RemoteException;
Dan Egnorbb9001c2009-07-27 12:20:13 -070061import android.os.SystemClock;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070062import android.os.WorkSource;
Oscar Montemayora8529f62009-11-18 10:14:20 -080063import android.provider.Settings;
Dan Egnorbb9001c2009-07-27 12:20:13 -070064import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080065import android.util.Slog;
Christopher Tate487529a2009-04-29 14:03:25 -070066import android.util.SparseArray;
Christopher Tate44a27902010-01-27 17:15:49 -080067import android.util.SparseIntArray;
Christopher Tate487529a2009-04-29 14:03:25 -070068
Christopher Tatecde87f42009-06-12 12:55:53 -070069import java.io.EOFException;
Christopher Tate22b87872009-05-04 16:41:53 -070070import java.io.File;
Joe Onoratob1a7ffe2009-05-06 18:06:21 -070071import java.io.FileDescriptor;
Christopher Tate1168baa2010-02-17 13:03:40 -080072import java.io.FileNotFoundException;
Christopher Tate4cc86e12009-09-21 19:36:51 -070073import java.io.FileOutputStream;
Christopher Tatec7b31e32009-06-10 15:49:30 -070074import java.io.IOException;
Joe Onoratob1a7ffe2009-05-06 18:06:21 -070075import java.io.PrintWriter;
Christopher Tatecde87f42009-06-12 12:55:53 -070076import java.io.RandomAccessFile;
Joe Onorato8ad02812009-05-13 01:41:44 -040077import java.util.ArrayList;
78import java.util.HashMap;
Christopher Tate487529a2009-04-29 14:03:25 -070079import java.util.HashSet;
80import java.util.List;
Christopher Tate91717492009-06-26 21:07:13 -070081import java.util.Map;
Dan Egnorc1c49c02009-10-30 17:35:39 -070082import java.util.Random;
Christopher Tateb49ceb32010-02-08 16:22:24 -080083import java.util.Set;
Christopher Tate487529a2009-04-29 14:03:25 -070084
85class BackupManagerService extends IBackupManager.Stub {
86 private static final String TAG = "BackupManagerService";
Chris Tatea9c50432010-10-11 14:37:12 -070087 private static final boolean DEBUG = true;
Christopher Tateaa088442009-06-16 18:25:46 -070088
Christopher Tate49401dd2009-07-01 12:34:29 -070089 // How often we perform a backup pass. Privileged external callers can
90 // trigger an immediate pass.
Christopher Tateb6787f22009-07-02 17:40:45 -070091 private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
Christopher Tate487529a2009-04-29 14:03:25 -070092
Dan Egnorc1c49c02009-10-30 17:35:39 -070093 // Random variation in backup scheduling time to avoid server load spikes
94 private static final int FUZZ_MILLIS = 5 * 60 * 1000;
95
Christopher Tate8031a3d2009-07-06 16:36:05 -070096 // The amount of time between the initial provisioning of the device and
97 // the first backup pass.
98 private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
99
Christopher Tate45281862010-03-05 15:46:30 -0800100 private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
101 private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
102 private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
Christopher Tate487529a2009-04-29 14:03:25 -0700103 private static final int MSG_RUN_BACKUP = 1;
Christopher Tate043dadc2009-06-02 16:11:00 -0700104 private static final int MSG_RUN_FULL_BACKUP = 2;
Christopher Tate9bbc21a2009-06-10 20:23:25 -0700105 private static final int MSG_RUN_RESTORE = 3;
Christopher Tateee0e78a2009-07-02 11:17:03 -0700106 private static final int MSG_RUN_CLEAR = 4;
Christopher Tate4cc86e12009-09-21 19:36:51 -0700107 private static final int MSG_RUN_INITIALIZE = 5;
Christopher Tate2d449afe2010-03-29 19:14:24 -0700108 private static final int MSG_RUN_GET_RESTORE_SETS = 6;
109 private static final int MSG_TIMEOUT = 7;
Christopher Tate73a3cb32010-12-13 18:27:26 -0800110 private static final int MSG_RESTORE_TIMEOUT = 8;
Christopher Tatec7b31e32009-06-10 15:49:30 -0700111
112 // Timeout interval for deciding that a bind or clear-data has taken too long
113 static final long TIMEOUT_INTERVAL = 10 * 1000;
114
Christopher Tate44a27902010-01-27 17:15:49 -0800115 // Timeout intervals for agent backup & restore operations
116 static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
117 static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
118
Christopher Tate487529a2009-04-29 14:03:25 -0700119 private Context mContext;
120 private PackageManager mPackageManager;
Christopher Tate1bb69062010-02-19 17:02:12 -0800121 IPackageManager mPackageManagerBinder;
Christopher Tate6ef58a12009-06-29 14:56:28 -0700122 private IActivityManager mActivityManager;
Christopher Tateb6787f22009-07-02 17:40:45 -0700123 private PowerManager mPowerManager;
124 private AlarmManager mAlarmManager;
Christopher Tate44a27902010-01-27 17:15:49 -0800125 IBackupManager mBackupManagerBinder;
Christopher Tateb6787f22009-07-02 17:40:45 -0700126
Christopher Tate73e02522009-07-15 14:18:26 -0700127 boolean mEnabled; // access to this is synchronized on 'this'
128 boolean mProvisioned;
Christopher Tatecce9da52010-02-03 15:11:15 -0800129 boolean mAutoRestore;
Christopher Tate73e02522009-07-15 14:18:26 -0700130 PowerManager.WakeLock mWakelock;
Christopher Tate44a27902010-01-27 17:15:49 -0800131 HandlerThread mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
132 BackupHandler mBackupHandler;
Christopher Tate4cc86e12009-09-21 19:36:51 -0700133 PendingIntent mRunBackupIntent, mRunInitIntent;
134 BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
Christopher Tate487529a2009-04-29 14:03:25 -0700135 // map UIDs to the set of backup client services within that UID's app set
Christopher Tate73e02522009-07-15 14:18:26 -0700136 final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
Christopher Tate181fafa2009-05-14 11:12:14 -0700137 = new SparseArray<HashSet<ApplicationInfo>>();
Christopher Tate487529a2009-04-29 14:03:25 -0700138 // set of backup services that have pending changes
Christopher Tate73e02522009-07-15 14:18:26 -0700139 class BackupRequest {
Christopher Tate181fafa2009-05-14 11:12:14 -0700140 public ApplicationInfo appInfo;
Christopher Tate46758122009-05-06 11:22:00 -0700141 public boolean fullBackup;
Christopher Tateaa088442009-06-16 18:25:46 -0700142
Christopher Tate181fafa2009-05-14 11:12:14 -0700143 BackupRequest(ApplicationInfo app, boolean isFull) {
144 appInfo = app;
Christopher Tate46758122009-05-06 11:22:00 -0700145 fullBackup = isFull;
146 }
Christopher Tate181fafa2009-05-14 11:12:14 -0700147
Jason parks1125d782011-01-12 09:47:26 -0600148 @Override
Christopher Tate181fafa2009-05-14 11:12:14 -0700149 public String toString() {
150 return "BackupRequest{app=" + appInfo + " full=" + fullBackup + "}";
151 }
Christopher Tate46758122009-05-06 11:22:00 -0700152 }
Christopher Tatec28083a2010-12-14 16:16:44 -0800153 // Backups that we haven't started yet. Keys are package names.
154 HashMap<String,BackupRequest> mPendingBackups
155 = new HashMap<String,BackupRequest>();
Christopher Tate5cb400b2009-06-25 16:03:14 -0700156
157 // Pseudoname that we use for the Package Manager metadata "package"
Christopher Tate73e02522009-07-15 14:18:26 -0700158 static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
Christopher Tate6aa41f42009-06-19 14:14:22 -0700159
160 // locking around the pending-backup management
Christopher Tate73e02522009-07-15 14:18:26 -0700161 final Object mQueueLock = new Object();
Christopher Tate487529a2009-04-29 14:03:25 -0700162
Christopher Tate043dadc2009-06-02 16:11:00 -0700163 // The thread performing the sequence of queued backups binds to each app's agent
164 // in succession. Bind notifications are asynchronously delivered through the
165 // Activity Manager; use this lock object to signal when a requested binding has
166 // completed.
Christopher Tate73e02522009-07-15 14:18:26 -0700167 final Object mAgentConnectLock = new Object();
168 IBackupAgent mConnectedAgent;
169 volatile boolean mConnecting;
Christopher Tate55f931a2009-09-29 17:17:34 -0700170 volatile long mLastBackupPass;
171 volatile long mNextBackupPass;
Christopher Tate043dadc2009-06-02 16:11:00 -0700172
Christopher Tate55f931a2009-09-29 17:17:34 -0700173 // A similar synchronization mechanism around clearing apps' data for restore
Christopher Tate73e02522009-07-15 14:18:26 -0700174 final Object mClearDataLock = new Object();
175 volatile boolean mClearingData;
Christopher Tatec7b31e32009-06-10 15:49:30 -0700176
Christopher Tate91717492009-06-26 21:07:13 -0700177 // Transport bookkeeping
Christopher Tate73e02522009-07-15 14:18:26 -0700178 final HashMap<String,IBackupTransport> mTransports
Christopher Tate91717492009-06-26 21:07:13 -0700179 = new HashMap<String,IBackupTransport>();
Christopher Tate73e02522009-07-15 14:18:26 -0700180 String mCurrentTransport;
181 IBackupTransport mLocalTransport, mGoogleTransport;
Christopher Tate80202c82010-01-25 19:37:47 -0800182 ActiveRestoreSession mActiveRestoreSession;
Christopher Tate043dadc2009-06-02 16:11:00 -0700183
Christopher Tate2d449afe2010-03-29 19:14:24 -0700184 class RestoreGetSetsParams {
185 public IBackupTransport transport;
186 public ActiveRestoreSession session;
187 public IRestoreObserver observer;
188
189 RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
190 IRestoreObserver _observer) {
191 transport = _transport;
192 session = _session;
193 observer = _observer;
194 }
195 }
196
Christopher Tate73e02522009-07-15 14:18:26 -0700197 class RestoreParams {
Christopher Tate7d562ec2009-06-25 18:03:43 -0700198 public IBackupTransport transport;
199 public IRestoreObserver observer;
Dan Egnor156411d2009-06-26 13:20:02 -0700200 public long token;
Christopher Tate84725812010-02-04 15:52:40 -0800201 public PackageInfo pkgInfo;
Christopher Tate1bb69062010-02-19 17:02:12 -0800202 public int pmToken; // in post-install restore, the PM's token for this transaction
Chris Tate249345b2010-10-29 12:57:04 -0700203 public boolean needFullBackup;
Christopher Tate84725812010-02-04 15:52:40 -0800204
205 RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
Chris Tate249345b2010-10-29 12:57:04 -0700206 long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
Christopher Tate84725812010-02-04 15:52:40 -0800207 transport = _transport;
208 observer = _obs;
209 token = _token;
210 pkgInfo = _pkg;
Christopher Tate1bb69062010-02-19 17:02:12 -0800211 pmToken = _pmToken;
Chris Tate249345b2010-10-29 12:57:04 -0700212 needFullBackup = _needFullBackup;
Christopher Tate84725812010-02-04 15:52:40 -0800213 }
Christopher Tate7d562ec2009-06-25 18:03:43 -0700214
Chris Tate249345b2010-10-29 12:57:04 -0700215 RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
216 boolean _needFullBackup) {
Christopher Tate7d562ec2009-06-25 18:03:43 -0700217 transport = _transport;
218 observer = _obs;
Dan Egnor156411d2009-06-26 13:20:02 -0700219 token = _token;
Christopher Tate84725812010-02-04 15:52:40 -0800220 pkgInfo = null;
Christopher Tate1bb69062010-02-19 17:02:12 -0800221 pmToken = 0;
Chris Tate249345b2010-10-29 12:57:04 -0700222 needFullBackup = _needFullBackup;
Christopher Tate7d562ec2009-06-25 18:03:43 -0700223 }
224 }
225
Christopher Tate73e02522009-07-15 14:18:26 -0700226 class ClearParams {
Christopher Tateee0e78a2009-07-02 11:17:03 -0700227 public IBackupTransport transport;
228 public PackageInfo packageInfo;
229
230 ClearParams(IBackupTransport _transport, PackageInfo _info) {
231 transport = _transport;
232 packageInfo = _info;
233 }
234 }
235
Christopher Tate44a27902010-01-27 17:15:49 -0800236 // Bookkeeping of in-flight operations for timeout etc. purposes. The operation
237 // token is the index of the entry in the pending-operations list.
238 static final int OP_PENDING = 0;
239 static final int OP_ACKNOWLEDGED = 1;
240 static final int OP_TIMEOUT = -1;
241
242 final SparseIntArray mCurrentOperations = new SparseIntArray();
243 final Object mCurrentOpLock = new Object();
244 final Random mTokenGenerator = new Random();
245
Christopher Tate5cb400b2009-06-25 16:03:14 -0700246 // Where we keep our journal files and other bookkeeping
Christopher Tate73e02522009-07-15 14:18:26 -0700247 File mBaseStateDir;
248 File mDataDir;
249 File mJournalDir;
250 File mJournal;
Christopher Tate73e02522009-07-15 14:18:26 -0700251
Christopher Tate84725812010-02-04 15:52:40 -0800252 // Keep a log of all the apps we've ever backed up, and what the
253 // dataset tokens are for both the current backup dataset and
254 // the ancestral dataset.
Christopher Tate73e02522009-07-15 14:18:26 -0700255 private File mEverStored;
Christopher Tate73e02522009-07-15 14:18:26 -0700256 HashSet<String> mEverStoredApps = new HashSet<String>();
257
Christopher Tateb49ceb32010-02-08 16:22:24 -0800258 static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes
Christopher Tate84725812010-02-04 15:52:40 -0800259 File mTokenFile;
Christopher Tateb49ceb32010-02-08 16:22:24 -0800260 Set<String> mAncestralPackages = null;
Christopher Tate84725812010-02-04 15:52:40 -0800261 long mAncestralToken = 0;
262 long mCurrentToken = 0;
263
Christopher Tate4cc86e12009-09-21 19:36:51 -0700264 // Persistently track the need to do a full init
265 static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
266 HashSet<String> mPendingInits = new HashSet<String>(); // transport names
Christopher Tateaa088442009-06-16 18:25:46 -0700267
Christopher Tate44a27902010-01-27 17:15:49 -0800268 // ----- Asynchronous backup/restore handler thread -----
269
270 private class BackupHandler extends Handler {
271 public BackupHandler(Looper looper) {
272 super(looper);
273 }
274
Jason parks1125d782011-01-12 09:47:26 -0600275 @Override
Christopher Tate44a27902010-01-27 17:15:49 -0800276 public void handleMessage(Message msg) {
277
278 switch (msg.what) {
279 case MSG_RUN_BACKUP:
280 {
281 mLastBackupPass = System.currentTimeMillis();
282 mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
283
284 IBackupTransport transport = getTransport(mCurrentTransport);
285 if (transport == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800286 Slog.v(TAG, "Backup requested but no transport available");
Christopher Tate44a27902010-01-27 17:15:49 -0800287 mWakelock.release();
288 break;
289 }
290
291 // snapshot the pending-backup set and work on that
292 ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
Christopher Tatec61da312010-02-05 10:41:27 -0800293 File oldJournal = mJournal;
Christopher Tate44a27902010-01-27 17:15:49 -0800294 synchronized (mQueueLock) {
Christopher Tatec61da312010-02-05 10:41:27 -0800295 // Do we have any work to do? Construct the work queue
296 // then release the synchronization lock to actually run
297 // the backup.
Christopher Tate44a27902010-01-27 17:15:49 -0800298 if (mPendingBackups.size() > 0) {
299 for (BackupRequest b: mPendingBackups.values()) {
300 queue.add(b);
301 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800302 if (DEBUG) Slog.v(TAG, "clearing pending backups");
Christopher Tate44a27902010-01-27 17:15:49 -0800303 mPendingBackups.clear();
304
305 // Start a new backup-queue journal file too
Christopher Tate44a27902010-01-27 17:15:49 -0800306 mJournal = null;
307
Christopher Tate44a27902010-01-27 17:15:49 -0800308 }
309 }
Christopher Tatec61da312010-02-05 10:41:27 -0800310
311 if (queue.size() > 0) {
312 // At this point, we have started a new journal file, and the old
313 // file identity is being passed to the backup processing thread.
314 // When it completes successfully, that old journal file will be
315 // deleted. If we crash prior to that, the old journal is parsed
316 // at next boot and the journaled requests fulfilled.
317 (new PerformBackupTask(transport, queue, oldJournal)).run();
318 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800319 Slog.v(TAG, "Backup requested but nothing pending");
Christopher Tatec61da312010-02-05 10:41:27 -0800320 mWakelock.release();
321 }
Christopher Tate44a27902010-01-27 17:15:49 -0800322 break;
323 }
324
325 case MSG_RUN_FULL_BACKUP:
326 break;
327
328 case MSG_RUN_RESTORE:
329 {
330 RestoreParams params = (RestoreParams)msg.obj;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800331 Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
Christopher Tate44a27902010-01-27 17:15:49 -0800332 (new PerformRestoreTask(params.transport, params.observer,
Chris Tate249345b2010-10-29 12:57:04 -0700333 params.token, params.pkgInfo, params.pmToken,
334 params.needFullBackup)).run();
Christopher Tate44a27902010-01-27 17:15:49 -0800335 break;
336 }
337
338 case MSG_RUN_CLEAR:
339 {
340 ClearParams params = (ClearParams)msg.obj;
341 (new PerformClearTask(params.transport, params.packageInfo)).run();
342 break;
343 }
344
345 case MSG_RUN_INITIALIZE:
346 {
347 HashSet<String> queue;
348
349 // Snapshot the pending-init queue and work on that
350 synchronized (mQueueLock) {
351 queue = new HashSet<String>(mPendingInits);
352 mPendingInits.clear();
353 }
354
355 (new PerformInitializeTask(queue)).run();
356 break;
357 }
358
Christopher Tate2d449afe2010-03-29 19:14:24 -0700359 case MSG_RUN_GET_RESTORE_SETS:
360 {
361 // Like other async operations, this is entered with the wakelock held
362 RestoreSet[] sets = null;
363 RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
364 try {
365 sets = params.transport.getAvailableRestoreSets();
366 // cache the result in the active session
367 synchronized (params.session) {
368 params.session.mRestoreSets = sets;
369 }
370 if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
371 } catch (Exception e) {
372 Slog.e(TAG, "Error from transport getting set list");
373 } finally {
374 if (params.observer != null) {
375 try {
376 params.observer.restoreSetsAvailable(sets);
377 } catch (RemoteException re) {
378 Slog.e(TAG, "Unable to report listing to observer");
379 } catch (Exception e) {
380 Slog.e(TAG, "Restore observer threw", e);
381 }
382 }
383
384 mWakelock.release();
385 }
386 break;
387 }
388
Christopher Tate44a27902010-01-27 17:15:49 -0800389 case MSG_TIMEOUT:
390 {
391 synchronized (mCurrentOpLock) {
392 final int token = msg.arg1;
393 int state = mCurrentOperations.get(token, OP_TIMEOUT);
394 if (state == OP_PENDING) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800395 if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + token);
Christopher Tate44a27902010-01-27 17:15:49 -0800396 mCurrentOperations.put(token, OP_TIMEOUT);
397 }
398 mCurrentOpLock.notifyAll();
399 }
400 break;
401 }
Christopher Tate73a3cb32010-12-13 18:27:26 -0800402
403 case MSG_RESTORE_TIMEOUT:
404 {
405 synchronized (BackupManagerService.this) {
406 if (mActiveRestoreSession != null) {
407 // Client app left the restore session dangling. We know that it
408 // can't be in the middle of an actual restore operation because
409 // those are executed serially on this same handler thread. Clean
410 // up now.
411 Slog.w(TAG, "Restore session timed out; aborting");
412 post(mActiveRestoreSession.new EndRestoreRunnable(
413 BackupManagerService.this, mActiveRestoreSession));
414 }
415 }
416 }
Christopher Tate44a27902010-01-27 17:15:49 -0800417 }
418 }
419 }
420
421 // ----- Main service implementation -----
422
Christopher Tate487529a2009-04-29 14:03:25 -0700423 public BackupManagerService(Context context) {
424 mContext = context;
425 mPackageManager = context.getPackageManager();
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700426 mPackageManagerBinder = AppGlobals.getPackageManager();
Christopher Tate181fafa2009-05-14 11:12:14 -0700427 mActivityManager = ActivityManagerNative.getDefault();
Christopher Tate487529a2009-04-29 14:03:25 -0700428
Christopher Tateb6787f22009-07-02 17:40:45 -0700429 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
430 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
431
Christopher Tate44a27902010-01-27 17:15:49 -0800432 mBackupManagerBinder = asInterface(asBinder());
433
434 // spin up the backup/restore handler thread
435 mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
436 mHandlerThread.start();
437 mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
438
Christopher Tate22b87872009-05-04 16:41:53 -0700439 // Set up our bookkeeping
Christopher Tateb6787f22009-07-02 17:40:45 -0700440 boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
Dianne Hackborncf098292009-07-01 19:55:20 -0700441 Settings.Secure.BACKUP_ENABLED, 0) != 0;
Christopher Tate8031a3d2009-07-06 16:36:05 -0700442 mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
Joe Onoratoab9a2a52009-07-27 08:56:39 -0700443 Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
Christopher Tatecce9da52010-02-03 15:11:15 -0800444 mAutoRestore = Settings.Secure.getInt(context.getContentResolver(),
Christopher Tate5035fda2010-02-25 18:01:14 -0800445 Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
Oscar Montemayora8529f62009-11-18 10:14:20 -0800446 // If Encrypted file systems is enabled or disabled, this call will return the
447 // correct directory.
Jason parks1125d782011-01-12 09:47:26 -0600448 mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
Oscar Montemayora8529f62009-11-18 10:14:20 -0800449 mBaseStateDir.mkdirs();
Christopher Tatef4172472009-05-05 15:50:03 -0700450 mDataDir = Environment.getDownloadCacheDirectory();
Christopher Tate9bbc21a2009-06-10 20:23:25 -0700451
Christopher Tate4cc86e12009-09-21 19:36:51 -0700452 // Alarm receivers for scheduled backups & initialization operations
Christopher Tateb6787f22009-07-02 17:40:45 -0700453 mRunBackupReceiver = new RunBackupReceiver();
Christopher Tate4cc86e12009-09-21 19:36:51 -0700454 IntentFilter filter = new IntentFilter();
455 filter.addAction(RUN_BACKUP_ACTION);
456 context.registerReceiver(mRunBackupReceiver, filter,
457 android.Manifest.permission.BACKUP, null);
458
459 mRunInitReceiver = new RunInitializeReceiver();
460 filter = new IntentFilter();
461 filter.addAction(RUN_INITIALIZE_ACTION);
462 context.registerReceiver(mRunInitReceiver, filter,
463 android.Manifest.permission.BACKUP, null);
Christopher Tateb6787f22009-07-02 17:40:45 -0700464
465 Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
Christopher Tateb6787f22009-07-02 17:40:45 -0700466 backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
467 mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
468
Christopher Tate4cc86e12009-09-21 19:36:51 -0700469 Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
470 backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
471 mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
472
Christopher Tatecde87f42009-06-12 12:55:53 -0700473 // Set up the backup-request journaling
Christopher Tate5cb400b2009-06-25 16:03:14 -0700474 mJournalDir = new File(mBaseStateDir, "pending");
475 mJournalDir.mkdirs(); // creates mBaseStateDir along the way
Dan Egnor852f8e42009-09-30 11:20:45 -0700476 mJournal = null; // will be created on first use
Christopher Tatecde87f42009-06-12 12:55:53 -0700477
Christopher Tate73e02522009-07-15 14:18:26 -0700478 // Set up the various sorts of package tracking we do
479 initPackageTracking();
480
Christopher Tateabce4e82009-06-18 18:35:32 -0700481 // Build our mapping of uid to backup client services. This implicitly
482 // schedules a backup pass on the Package Manager metadata the first
483 // time anything needs to be backed up.
Christopher Tate3799bc22009-05-06 16:13:56 -0700484 synchronized (mBackupParticipants) {
485 addPackageParticipantsLocked(null);
Christopher Tate487529a2009-04-29 14:03:25 -0700486 }
487
Dan Egnor87a02bc2009-06-17 02:30:10 -0700488 // Set up our transport options and initialize the default transport
489 // TODO: Have transports register themselves somehow?
490 // TODO: Don't create transports that we don't need to?
Dan Egnor87a02bc2009-06-17 02:30:10 -0700491 mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
Christopher Tate91717492009-06-26 21:07:13 -0700492 ComponentName localName = new ComponentName(context, LocalTransport.class);
493 registerTransport(localName.flattenToShortString(), mLocalTransport);
Dan Egnor87a02bc2009-06-17 02:30:10 -0700494
Christopher Tate91717492009-06-26 21:07:13 -0700495 mGoogleTransport = null;
Dianne Hackborncf098292009-07-01 19:55:20 -0700496 mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
497 Settings.Secure.BACKUP_TRANSPORT);
498 if ("".equals(mCurrentTransport)) {
499 mCurrentTransport = null;
Christopher Tatece0bf062009-07-01 11:43:53 -0700500 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800501 if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
Christopher Tate91717492009-06-26 21:07:13 -0700502
503 // Attach to the Google backup transport. When this comes up, it will set
504 // itself as the current transport because we explicitly reset mCurrentTransport
505 // to null.
Christopher Tatea32504f2010-04-21 17:58:07 -0700506 ComponentName transportComponent = new ComponentName("com.google.android.backup",
507 "com.google.android.backup.BackupTransportService");
508 try {
509 // If there's something out there that is supposed to be the Google
510 // backup transport, make sure it's legitimately part of the OS build
511 // and not an app lying about its package name.
512 ApplicationInfo info = mPackageManager.getApplicationInfo(
513 transportComponent.getPackageName(), 0);
514 if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
515 if (DEBUG) Slog.v(TAG, "Binding to Google transport");
516 Intent intent = new Intent().setComponent(transportComponent);
517 context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
518 } else {
519 Slog.w(TAG, "Possible Google transport spoof: ignoring " + info);
520 }
521 } catch (PackageManager.NameNotFoundException nnf) {
522 // No such package? No binding.
523 if (DEBUG) Slog.v(TAG, "Google transport not present");
524 }
Christopher Tateaa088442009-06-16 18:25:46 -0700525
Christopher Tatecde87f42009-06-12 12:55:53 -0700526 // Now that we know about valid backup participants, parse any
Christopher Tate49401dd2009-07-01 12:34:29 -0700527 // leftover journal files into the pending backup set
Christopher Tatecde87f42009-06-12 12:55:53 -0700528 parseLeftoverJournals();
529
Christopher Tateb6787f22009-07-02 17:40:45 -0700530 // Power management
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700531 mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
Christopher Tateb6787f22009-07-02 17:40:45 -0700532
533 // Start the backup passes going
534 setBackupEnabled(areEnabled);
535 }
536
537 private class RunBackupReceiver extends BroadcastReceiver {
Jason parks1125d782011-01-12 09:47:26 -0600538 @Override
Christopher Tateb6787f22009-07-02 17:40:45 -0700539 public void onReceive(Context context, Intent intent) {
540 if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
Christopher Tateb6787f22009-07-02 17:40:45 -0700541 synchronized (mQueueLock) {
Christopher Tate4cc86e12009-09-21 19:36:51 -0700542 if (mPendingInits.size() > 0) {
543 // If there are pending init operations, we process those
544 // and then settle into the usual periodic backup schedule.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800545 if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
Christopher Tate4cc86e12009-09-21 19:36:51 -0700546 try {
547 mAlarmManager.cancel(mRunInitIntent);
548 mRunInitIntent.send();
549 } catch (PendingIntent.CanceledException ce) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800550 Slog.e(TAG, "Run init intent cancelled");
Christopher Tate4cc86e12009-09-21 19:36:51 -0700551 // can't really do more than bail here
552 }
553 } else {
Christopher Tatec2af5d32010-02-02 15:18:58 -0800554 // Don't run backups now if we're disabled or not yet
555 // fully set up.
556 if (mEnabled && mProvisioned) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800557 if (DEBUG) Slog.v(TAG, "Running a backup pass");
Christopher Tate4cc86e12009-09-21 19:36:51 -0700558
559 // Acquire the wakelock and pass it to the backup thread. it will
560 // be released once backup concludes.
561 mWakelock.acquire();
562
563 Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
564 mBackupHandler.sendMessage(msg);
565 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800566 Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
Christopher Tate4cc86e12009-09-21 19:36:51 -0700567 }
568 }
569 }
570 }
571 }
572 }
573
574 private class RunInitializeReceiver extends BroadcastReceiver {
Jason parks1125d782011-01-12 09:47:26 -0600575 @Override
Christopher Tate4cc86e12009-09-21 19:36:51 -0700576 public void onReceive(Context context, Intent intent) {
577 if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
578 synchronized (mQueueLock) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800579 if (DEBUG) Slog.v(TAG, "Running a device init");
Christopher Tate4cc86e12009-09-21 19:36:51 -0700580
581 // Acquire the wakelock and pass it to the init thread. it will
582 // be released once init concludes.
Christopher Tateb6787f22009-07-02 17:40:45 -0700583 mWakelock.acquire();
584
Christopher Tate4cc86e12009-09-21 19:36:51 -0700585 Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
Christopher Tateb6787f22009-07-02 17:40:45 -0700586 mBackupHandler.sendMessage(msg);
587 }
588 }
Christopher Tate49401dd2009-07-01 12:34:29 -0700589 }
Christopher Tateb6787f22009-07-02 17:40:45 -0700590 }
Christopher Tate3799bc22009-05-06 16:13:56 -0700591
Christopher Tate73e02522009-07-15 14:18:26 -0700592 private void initPackageTracking() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800593 if (DEBUG) Slog.v(TAG, "Initializing package tracking");
Christopher Tate73e02522009-07-15 14:18:26 -0700594
Christopher Tate84725812010-02-04 15:52:40 -0800595 // Remember our ancestral dataset
596 mTokenFile = new File(mBaseStateDir, "ancestral");
597 try {
598 RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
Christopher Tateb49ceb32010-02-08 16:22:24 -0800599 int version = tf.readInt();
600 if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
601 mAncestralToken = tf.readLong();
602 mCurrentToken = tf.readLong();
603
604 int numPackages = tf.readInt();
605 if (numPackages >= 0) {
606 mAncestralPackages = new HashSet<String>();
607 for (int i = 0; i < numPackages; i++) {
608 String pkgName = tf.readUTF();
609 mAncestralPackages.add(pkgName);
610 }
611 }
612 }
Brad Fitzpatrick725d8f02010-11-15 11:12:42 -0800613 tf.close();
Christopher Tate1168baa2010-02-17 13:03:40 -0800614 } catch (FileNotFoundException fnf) {
615 // Probably innocuous
Joe Onorato8a9b2202010-02-26 18:56:32 -0800616 Slog.v(TAG, "No ancestral data");
Christopher Tate84725812010-02-04 15:52:40 -0800617 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800618 Slog.w(TAG, "Unable to read token file", e);
Christopher Tate84725812010-02-04 15:52:40 -0800619 }
620
Christopher Tatee97e8072009-07-15 16:45:50 -0700621 // Keep a log of what apps we've ever backed up. Because we might have
622 // rebooted in the middle of an operation that was removing something from
623 // this log, we sanity-check its contents here and reconstruct it.
Christopher Tate73e02522009-07-15 14:18:26 -0700624 mEverStored = new File(mBaseStateDir, "processed");
Christopher Tatee97e8072009-07-15 16:45:50 -0700625 File tempProcessedFile = new File(mBaseStateDir, "processed.new");
Christopher Tate73e02522009-07-15 14:18:26 -0700626
Christopher Tatee97e8072009-07-15 16:45:50 -0700627 // If we were in the middle of removing something from the ever-backed-up
628 // file, there might be a transient "processed.new" file still present.
Dan Egnor852f8e42009-09-30 11:20:45 -0700629 // Ignore it -- we'll validate "processed" against the current package set.
Christopher Tatee97e8072009-07-15 16:45:50 -0700630 if (tempProcessedFile.exists()) {
631 tempProcessedFile.delete();
632 }
633
Dan Egnor852f8e42009-09-30 11:20:45 -0700634 // If there are previous contents, parse them out then start a new
635 // file to continue the recordkeeping.
636 if (mEverStored.exists()) {
637 RandomAccessFile temp = null;
638 RandomAccessFile in = null;
639
640 try {
641 temp = new RandomAccessFile(tempProcessedFile, "rws");
642 in = new RandomAccessFile(mEverStored, "r");
643
644 while (true) {
645 PackageInfo info;
646 String pkg = in.readUTF();
647 try {
648 info = mPackageManager.getPackageInfo(pkg, 0);
649 mEverStoredApps.add(pkg);
650 temp.writeUTF(pkg);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800651 if (DEBUG) Slog.v(TAG, " + " + pkg);
Dan Egnor852f8e42009-09-30 11:20:45 -0700652 } catch (NameNotFoundException e) {
653 // nope, this package was uninstalled; don't include it
Joe Onorato8a9b2202010-02-26 18:56:32 -0800654 if (DEBUG) Slog.v(TAG, " - " + pkg);
Dan Egnor852f8e42009-09-30 11:20:45 -0700655 }
656 }
657 } catch (EOFException e) {
658 // Once we've rewritten the backup history log, atomically replace the
659 // old one with the new one then reopen the file for continuing use.
660 if (!tempProcessedFile.renameTo(mEverStored)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800661 Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
Dan Egnor852f8e42009-09-30 11:20:45 -0700662 }
663 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800664 Slog.e(TAG, "Error in processed file", e);
Dan Egnor852f8e42009-09-30 11:20:45 -0700665 } finally {
666 try { if (temp != null) temp.close(); } catch (IOException e) {}
667 try { if (in != null) in.close(); } catch (IOException e) {}
668 }
669 }
670
Christopher Tate73e02522009-07-15 14:18:26 -0700671 // Register for broadcasts about package install, etc., so we can
672 // update the provider list.
673 IntentFilter filter = new IntentFilter();
674 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
675 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
676 filter.addDataScheme("package");
677 mContext.registerReceiver(mBroadcastReceiver, filter);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800678 // Register for events related to sdcard installation.
679 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800680 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
681 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800682 mContext.registerReceiver(mBroadcastReceiver, sdFilter);
Christopher Tate73e02522009-07-15 14:18:26 -0700683 }
684
Christopher Tatecde87f42009-06-12 12:55:53 -0700685 private void parseLeftoverJournals() {
Dan Egnor852f8e42009-09-30 11:20:45 -0700686 for (File f : mJournalDir.listFiles()) {
687 if (mJournal == null || f.compareTo(mJournal) != 0) {
688 // This isn't the current journal, so it must be a leftover. Read
689 // out the package names mentioned there and schedule them for
690 // backup.
691 RandomAccessFile in = null;
692 try {
Joe Onorato431bb222010-10-18 19:13:23 -0400693 Slog.i(TAG, "Found stale backup journal, scheduling");
Dan Egnor852f8e42009-09-30 11:20:45 -0700694 in = new RandomAccessFile(f, "r");
695 while (true) {
696 String packageName = in.readUTF();
Joe Onorato431bb222010-10-18 19:13:23 -0400697 Slog.i(TAG, " " + packageName);
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -0700698 dataChangedImpl(packageName);
Christopher Tatecde87f42009-06-12 12:55:53 -0700699 }
Dan Egnor852f8e42009-09-30 11:20:45 -0700700 } catch (EOFException e) {
701 // no more data; we're done
702 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800703 Slog.e(TAG, "Can't read " + f, e);
Dan Egnor852f8e42009-09-30 11:20:45 -0700704 } finally {
705 // close/delete the file
706 try { if (in != null) in.close(); } catch (IOException e) {}
707 f.delete();
Christopher Tatecde87f42009-06-12 12:55:53 -0700708 }
709 }
710 }
711 }
712
Christopher Tate4cc86e12009-09-21 19:36:51 -0700713 // Maintain persistent state around whether need to do an initialize operation.
714 // Must be called with the queue lock held.
715 void recordInitPendingLocked(boolean isPending, String transportName) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800716 if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
Christopher Tate4cc86e12009-09-21 19:36:51 -0700717 + " on transport " + transportName);
718 try {
719 IBackupTransport transport = getTransport(transportName);
720 String transportDirName = transport.transportDirName();
721 File stateDir = new File(mBaseStateDir, transportDirName);
722 File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
723
724 if (isPending) {
725 // We need an init before we can proceed with sending backup data.
726 // Record that with an entry in our set of pending inits, as well as
727 // journaling it via creation of a sentinel file.
728 mPendingInits.add(transportName);
729 try {
730 (new FileOutputStream(initPendingFile)).close();
731 } catch (IOException ioe) {
732 // Something is badly wrong with our permissions; just try to move on
733 }
734 } else {
735 // No more initialization needed; wipe the journal and reset our state.
736 initPendingFile.delete();
737 mPendingInits.remove(transportName);
738 }
739 } catch (RemoteException e) {
740 // can't happen; the transport is local
741 }
742 }
743
Christopher Tated55e18a2009-09-21 10:12:59 -0700744 // Reset all of our bookkeeping, in response to having been told that
745 // the backend data has been wiped [due to idle expiry, for example],
746 // so we must re-upload all saved settings.
747 void resetBackupState(File stateFileDir) {
748 synchronized (mQueueLock) {
749 // Wipe the "what we've ever backed up" tracking
Christopher Tated55e18a2009-09-21 10:12:59 -0700750 mEverStoredApps.clear();
Dan Egnor852f8e42009-09-30 11:20:45 -0700751 mEverStored.delete();
Christopher Tated55e18a2009-09-21 10:12:59 -0700752
Christopher Tate84725812010-02-04 15:52:40 -0800753 mCurrentToken = 0;
754 writeRestoreTokens();
755
Christopher Tated55e18a2009-09-21 10:12:59 -0700756 // Remove all the state files
757 for (File sf : stateFileDir.listFiles()) {
Christopher Tate4cc86e12009-09-21 19:36:51 -0700758 // ... but don't touch the needs-init sentinel
759 if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
760 sf.delete();
761 }
Christopher Tated55e18a2009-09-21 10:12:59 -0700762 }
763
764 // Enqueue a new backup of every participant
765 int N = mBackupParticipants.size();
766 for (int i=0; i<N; i++) {
767 int uid = mBackupParticipants.keyAt(i);
768 HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
769 for (ApplicationInfo app: participants) {
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -0700770 dataChangedImpl(app.packageName);
Christopher Tated55e18a2009-09-21 10:12:59 -0700771 }
772 }
773 }
774 }
775
Christopher Tatedfa47b56e2009-12-22 16:01:32 -0800776 // Add a transport to our set of available backends. If 'transport' is null, this
777 // is an unregistration, and the transport's entry is removed from our bookkeeping.
Christopher Tate91717492009-06-26 21:07:13 -0700778 private void registerTransport(String name, IBackupTransport transport) {
779 synchronized (mTransports) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800780 if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport);
Christopher Tatedfa47b56e2009-12-22 16:01:32 -0800781 if (transport != null) {
782 mTransports.put(name, transport);
783 } else {
784 mTransports.remove(name);
Christopher Tateb0dcaaf2010-01-29 16:27:04 -0800785 if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) {
Christopher Tatedfa47b56e2009-12-22 16:01:32 -0800786 mCurrentTransport = null;
787 }
788 // Nothing further to do in the unregistration case
789 return;
790 }
Christopher Tate91717492009-06-26 21:07:13 -0700791 }
Christopher Tate4cc86e12009-09-21 19:36:51 -0700792
793 // If the init sentinel file exists, we need to be sure to perform the init
794 // as soon as practical. We also create the state directory at registration
795 // time to ensure it's present from the outset.
796 try {
797 String transportName = transport.transportDirName();
798 File stateDir = new File(mBaseStateDir, transportName);
799 stateDir.mkdirs();
800
801 File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
802 if (initSentinel.exists()) {
803 synchronized (mQueueLock) {
804 mPendingInits.add(transportName);
805
806 // TODO: pick a better starting time than now + 1 minute
807 long delay = 1000 * 60; // one minute, in milliseconds
808 mAlarmManager.set(AlarmManager.RTC_WAKEUP,
809 System.currentTimeMillis() + delay, mRunInitIntent);
810 }
811 }
812 } catch (RemoteException e) {
813 // can't happen, the transport is local
814 }
Christopher Tate91717492009-06-26 21:07:13 -0700815 }
816
Christopher Tate3799bc22009-05-06 16:13:56 -0700817 // ----- Track installation/removal of packages -----
818 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
Jason parks1125d782011-01-12 09:47:26 -0600819 @Override
Christopher Tate3799bc22009-05-06 16:13:56 -0700820 public void onReceive(Context context, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800821 if (DEBUG) Slog.d(TAG, "Received broadcast " + intent);
Christopher Tate3799bc22009-05-06 16:13:56 -0700822
Christopher Tate3799bc22009-05-06 16:13:56 -0700823 String action = intent.getAction();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800824 boolean replacing = false;
825 boolean added = false;
826 Bundle extras = intent.getExtras();
827 String pkgList[] = null;
828 if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
829 Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
830 Uri uri = intent.getData();
831 if (uri == null) {
832 return;
833 }
834 String pkgName = uri.getSchemeSpecificPart();
835 if (pkgName != null) {
836 pkgList = new String[] { pkgName };
837 }
838 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
839 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800840 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800841 added = true;
842 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800843 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800844 added = false;
845 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
846 }
847 if (pkgList == null || pkgList.length == 0) {
848 return;
849 }
850 if (added) {
Christopher Tate3799bc22009-05-06 16:13:56 -0700851 synchronized (mBackupParticipants) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800852 for (String pkgName : pkgList) {
853 if (replacing) {
854 // The package was just upgraded
855 updatePackageParticipantsLocked(pkgName);
856 } else {
857 // The package was just added
858 addPackageParticipantsLocked(pkgName);
859 }
Christopher Tate3799bc22009-05-06 16:13:56 -0700860 }
861 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800862 } else {
863 if (replacing) {
Christopher Tate3799bc22009-05-06 16:13:56 -0700864 // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
865 } else {
866 synchronized (mBackupParticipants) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800867 for (String pkgName : pkgList) {
868 removePackageParticipantsLocked(pkgName);
869 }
Christopher Tate3799bc22009-05-06 16:13:56 -0700870 }
871 }
872 }
873 }
874 };
875
Dan Egnor87a02bc2009-06-17 02:30:10 -0700876 // ----- Track connection to GoogleBackupTransport service -----
877 ServiceConnection mGoogleConnection = new ServiceConnection() {
878 public void onServiceConnected(ComponentName name, IBinder service) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800879 if (DEBUG) Slog.v(TAG, "Connected to Google transport");
Dan Egnor87a02bc2009-06-17 02:30:10 -0700880 mGoogleTransport = IBackupTransport.Stub.asInterface(service);
Christopher Tate91717492009-06-26 21:07:13 -0700881 registerTransport(name.flattenToShortString(), mGoogleTransport);
Dan Egnor87a02bc2009-06-17 02:30:10 -0700882 }
883
884 public void onServiceDisconnected(ComponentName name) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800885 if (DEBUG) Slog.v(TAG, "Disconnected from Google transport");
Dan Egnor87a02bc2009-06-17 02:30:10 -0700886 mGoogleTransport = null;
Christopher Tate91717492009-06-26 21:07:13 -0700887 registerTransport(name.flattenToShortString(), null);
Dan Egnor87a02bc2009-06-17 02:30:10 -0700888 }
889 };
890
Christopher Tate181fafa2009-05-14 11:12:14 -0700891 // Add the backup agents in the given package to our set of known backup participants.
892 // If 'packageName' is null, adds all backup agents in the whole system.
Christopher Tate3799bc22009-05-06 16:13:56 -0700893 void addPackageParticipantsLocked(String packageName) {
Christopher Tate181fafa2009-05-14 11:12:14 -0700894 // Look for apps that define the android:backupAgent attribute
Joe Onorato8a9b2202010-02-26 18:56:32 -0800895 if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: " + packageName);
Dan Egnorefe52642009-06-24 00:16:33 -0700896 List<PackageInfo> targetApps = allAgentPackages();
Christopher Tate181fafa2009-05-14 11:12:14 -0700897 addPackageParticipantsLockedInner(packageName, targetApps);
Christopher Tate3799bc22009-05-06 16:13:56 -0700898 }
899
Christopher Tate181fafa2009-05-14 11:12:14 -0700900 private void addPackageParticipantsLockedInner(String packageName,
Dan Egnorefe52642009-06-24 00:16:33 -0700901 List<PackageInfo> targetPkgs) {
Christopher Tate181fafa2009-05-14 11:12:14 -0700902 if (DEBUG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800903 Slog.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
Dan Egnorefe52642009-06-24 00:16:33 -0700904 for (PackageInfo p : targetPkgs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800905 Slog.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
Christopher Tate5e1ab332009-09-01 20:32:49 -0700906 + " uid=" + p.applicationInfo.uid
907 + " killAfterRestore="
908 + (((p.applicationInfo.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) ? "true" : "false")
Christopher Tate5e1ab332009-09-01 20:32:49 -0700909 );
Christopher Tate181fafa2009-05-14 11:12:14 -0700910 }
911 }
912
Dan Egnorefe52642009-06-24 00:16:33 -0700913 for (PackageInfo pkg : targetPkgs) {
914 if (packageName == null || pkg.packageName.equals(packageName)) {
915 int uid = pkg.applicationInfo.uid;
Christopher Tate181fafa2009-05-14 11:12:14 -0700916 HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
Christopher Tate3799bc22009-05-06 16:13:56 -0700917 if (set == null) {
Christopher Tate181fafa2009-05-14 11:12:14 -0700918 set = new HashSet<ApplicationInfo>();
Christopher Tate3799bc22009-05-06 16:13:56 -0700919 mBackupParticipants.put(uid, set);
920 }
Dan Egnorefe52642009-06-24 00:16:33 -0700921 set.add(pkg.applicationInfo);
Christopher Tate73e02522009-07-15 14:18:26 -0700922
923 // If we've never seen this app before, schedule a backup for it
924 if (!mEverStoredApps.contains(pkg.packageName)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800925 if (DEBUG) Slog.i(TAG, "New app " + pkg.packageName
Christopher Tate73e02522009-07-15 14:18:26 -0700926 + " never backed up; scheduling");
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -0700927 dataChangedImpl(pkg.packageName);
Christopher Tate73e02522009-07-15 14:18:26 -0700928 }
Christopher Tate3799bc22009-05-06 16:13:56 -0700929 }
Christopher Tate487529a2009-04-29 14:03:25 -0700930 }
931 }
932
Christopher Tate6785dd82009-06-18 15:58:25 -0700933 // Remove the given package's entry from our known active set. If
934 // 'packageName' is null, *all* participating apps will be removed.
Christopher Tate3799bc22009-05-06 16:13:56 -0700935 void removePackageParticipantsLocked(String packageName) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800936 if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: " + packageName);
Christopher Tatec28083a2010-12-14 16:16:44 -0800937 List<String> allApps = new ArrayList<String>();
Christopher Tate181fafa2009-05-14 11:12:14 -0700938 if (packageName != null) {
Christopher Tatec28083a2010-12-14 16:16:44 -0800939 allApps.add(packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -0700940 } else {
941 // all apps with agents
Christopher Tatec28083a2010-12-14 16:16:44 -0800942 List<PackageInfo> knownPackages = allAgentPackages();
943 for (PackageInfo pkg : knownPackages) {
944 allApps.add(pkg.packageName);
945 }
Christopher Tate181fafa2009-05-14 11:12:14 -0700946 }
947 removePackageParticipantsLockedInner(packageName, allApps);
Christopher Tate3799bc22009-05-06 16:13:56 -0700948 }
949
Joe Onorato8ad02812009-05-13 01:41:44 -0400950 private void removePackageParticipantsLockedInner(String packageName,
Christopher Tatec28083a2010-12-14 16:16:44 -0800951 List<String> allPackageNames) {
Christopher Tate043dadc2009-06-02 16:11:00 -0700952 if (DEBUG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800953 Slog.v(TAG, "removePackageParticipantsLockedInner (" + packageName
Christopher Tatec28083a2010-12-14 16:16:44 -0800954 + ") removing " + allPackageNames.size() + " entries");
955 for (String p : allPackageNames) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800956 Slog.v(TAG, " - " + p);
Christopher Tate043dadc2009-06-02 16:11:00 -0700957 }
958 }
Christopher Tatec28083a2010-12-14 16:16:44 -0800959 for (String pkg : allPackageNames) {
960 if (packageName == null || pkg.equals(packageName)) {
961 int uid = -1;
962 try {
963 PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
964 uid = info.applicationInfo.uid;
965 } catch (NameNotFoundException e) {
966 // we don't know this package name, so just skip it for now
967 continue;
968 }
969
Christopher Tate181fafa2009-05-14 11:12:14 -0700970 HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
Christopher Tate3799bc22009-05-06 16:13:56 -0700971 if (set != null) {
Christopher Tatecd4ff2e2009-06-05 13:57:54 -0700972 // Find the existing entry with the same package name, and remove it.
973 // We can't just remove(app) because the instances are different.
974 for (ApplicationInfo entry: set) {
Christopher Tatec28083a2010-12-14 16:16:44 -0800975 if (entry.packageName.equals(pkg)) {
976 if (DEBUG) Slog.v(TAG, " removing participant " + pkg);
Christopher Tatecd4ff2e2009-06-05 13:57:54 -0700977 set.remove(entry);
Christopher Tatec28083a2010-12-14 16:16:44 -0800978 removeEverBackedUp(pkg);
Christopher Tatecd4ff2e2009-06-05 13:57:54 -0700979 break;
980 }
981 }
Christopher Tate3799bc22009-05-06 16:13:56 -0700982 if (set.size() == 0) {
Dan Egnorefe52642009-06-24 00:16:33 -0700983 mBackupParticipants.delete(uid);
984 }
Christopher Tate3799bc22009-05-06 16:13:56 -0700985 }
986 }
987 }
988 }
989
Christopher Tate181fafa2009-05-14 11:12:14 -0700990 // Returns the set of all applications that define an android:backupAgent attribute
Christopher Tate73e02522009-07-15 14:18:26 -0700991 List<PackageInfo> allAgentPackages() {
Christopher Tate6785dd82009-06-18 15:58:25 -0700992 // !!! TODO: cache this and regenerate only when necessary
Dan Egnorefe52642009-06-24 00:16:33 -0700993 int flags = PackageManager.GET_SIGNATURES;
994 List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
995 int N = packages.size();
996 for (int a = N-1; a >= 0; a--) {
Christopher Tate0749dcd2009-08-13 15:13:03 -0700997 PackageInfo pkg = packages.get(a);
Christopher Tateb8eb1cb2009-09-16 10:57:21 -0700998 try {
999 ApplicationInfo app = pkg.applicationInfo;
1000 if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
Christopher Tatea87240c2010-02-12 14:12:34 -08001001 || app.backupAgentName == null) {
Christopher Tateb8eb1cb2009-09-16 10:57:21 -07001002 packages.remove(a);
1003 }
1004 else {
1005 // we will need the shared library path, so look that up and store it here
1006 app = mPackageManager.getApplicationInfo(pkg.packageName,
1007 PackageManager.GET_SHARED_LIBRARY_FILES);
1008 pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
1009 }
1010 } catch (NameNotFoundException e) {
Dan Egnorefe52642009-06-24 00:16:33 -07001011 packages.remove(a);
Christopher Tate181fafa2009-05-14 11:12:14 -07001012 }
1013 }
Dan Egnorefe52642009-06-24 00:16:33 -07001014 return packages;
Christopher Tate181fafa2009-05-14 11:12:14 -07001015 }
Christopher Tateaa088442009-06-16 18:25:46 -07001016
Christopher Tate3799bc22009-05-06 16:13:56 -07001017 // Reset the given package's known backup participants. Unlike add/remove, the update
1018 // action cannot be passed a null package name.
1019 void updatePackageParticipantsLocked(String packageName) {
1020 if (packageName == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001021 Slog.e(TAG, "updatePackageParticipants called with null package name");
Christopher Tate3799bc22009-05-06 16:13:56 -07001022 return;
1023 }
Joe Onorato8a9b2202010-02-26 18:56:32 -08001024 if (DEBUG) Slog.v(TAG, "updatePackageParticipantsLocked: " + packageName);
Christopher Tate3799bc22009-05-06 16:13:56 -07001025
1026 // brute force but small code size
Dan Egnorefe52642009-06-24 00:16:33 -07001027 List<PackageInfo> allApps = allAgentPackages();
Christopher Tatec28083a2010-12-14 16:16:44 -08001028 List<String> allAppNames = new ArrayList<String>();
1029 for (PackageInfo pkg : allApps) {
1030 allAppNames.add(pkg.packageName);
1031 }
1032 removePackageParticipantsLockedInner(packageName, allAppNames);
Christopher Tate181fafa2009-05-14 11:12:14 -07001033 addPackageParticipantsLockedInner(packageName, allApps);
Christopher Tate3799bc22009-05-06 16:13:56 -07001034 }
1035
Christopher Tate84725812010-02-04 15:52:40 -08001036 // Called from the backup task: record that the given app has been successfully
Christopher Tate73e02522009-07-15 14:18:26 -07001037 // backed up at least once
1038 void logBackupComplete(String packageName) {
Dan Egnor852f8e42009-09-30 11:20:45 -07001039 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
1040
1041 synchronized (mEverStoredApps) {
1042 if (!mEverStoredApps.add(packageName)) return;
1043
1044 RandomAccessFile out = null;
1045 try {
1046 out = new RandomAccessFile(mEverStored, "rws");
1047 out.seek(out.length());
1048 out.writeUTF(packageName);
1049 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001050 Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
Dan Egnor852f8e42009-09-30 11:20:45 -07001051 } finally {
1052 try { if (out != null) out.close(); } catch (IOException e) {}
Christopher Tate73e02522009-07-15 14:18:26 -07001053 }
1054 }
1055 }
1056
Christopher Tatee97e8072009-07-15 16:45:50 -07001057 // Remove our awareness of having ever backed up the given package
1058 void removeEverBackedUp(String packageName) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001059 if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName + ", new set:");
Christopher Tatee97e8072009-07-15 16:45:50 -07001060
Dan Egnor852f8e42009-09-30 11:20:45 -07001061 synchronized (mEverStoredApps) {
1062 // Rewrite the file and rename to overwrite. If we reboot in the middle,
1063 // we'll recognize on initialization time that the package no longer
1064 // exists and fix it up then.
1065 File tempKnownFile = new File(mBaseStateDir, "processed.new");
1066 RandomAccessFile known = null;
1067 try {
1068 known = new RandomAccessFile(tempKnownFile, "rws");
1069 mEverStoredApps.remove(packageName);
1070 for (String s : mEverStoredApps) {
1071 known.writeUTF(s);
Joe Onorato8a9b2202010-02-26 18:56:32 -08001072 if (DEBUG) Slog.v(TAG, " " + s);
Christopher Tatee97e8072009-07-15 16:45:50 -07001073 }
Dan Egnor852f8e42009-09-30 11:20:45 -07001074 known.close();
1075 known = null;
1076 if (!tempKnownFile.renameTo(mEverStored)) {
1077 throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
1078 }
1079 } catch (IOException e) {
1080 // Bad: we couldn't create the new copy. For safety's sake we
1081 // abandon the whole process and remove all what's-backed-up
1082 // state entirely, meaning we'll force a backup pass for every
1083 // participant on the next boot or [re]install.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001084 Slog.w(TAG, "Error rewriting " + mEverStored, e);
Dan Egnor852f8e42009-09-30 11:20:45 -07001085 mEverStoredApps.clear();
1086 tempKnownFile.delete();
1087 mEverStored.delete();
1088 } finally {
1089 try { if (known != null) known.close(); } catch (IOException e) {}
Christopher Tatee97e8072009-07-15 16:45:50 -07001090 }
1091 }
1092 }
1093
Christopher Tateb49ceb32010-02-08 16:22:24 -08001094 // Persistently record the current and ancestral backup tokens as well
1095 // as the set of packages with data [supposedly] available in the
1096 // ancestral dataset.
Christopher Tate84725812010-02-04 15:52:40 -08001097 void writeRestoreTokens() {
1098 try {
1099 RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
Christopher Tateb49ceb32010-02-08 16:22:24 -08001100
1101 // First, the version number of this record, for futureproofing
1102 af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
1103
1104 // Write the ancestral and current tokens
Christopher Tate84725812010-02-04 15:52:40 -08001105 af.writeLong(mAncestralToken);
1106 af.writeLong(mCurrentToken);
Christopher Tateb49ceb32010-02-08 16:22:24 -08001107
1108 // Now write the set of ancestral packages
1109 if (mAncestralPackages == null) {
1110 af.writeInt(-1);
1111 } else {
1112 af.writeInt(mAncestralPackages.size());
Joe Onorato8a9b2202010-02-26 18:56:32 -08001113 if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size());
Christopher Tateb49ceb32010-02-08 16:22:24 -08001114 for (String pkgName : mAncestralPackages) {
1115 af.writeUTF(pkgName);
Joe Onorato8a9b2202010-02-26 18:56:32 -08001116 if (DEBUG) Slog.v(TAG, " " + pkgName);
Christopher Tateb49ceb32010-02-08 16:22:24 -08001117 }
1118 }
Christopher Tate84725812010-02-04 15:52:40 -08001119 af.close();
1120 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001121 Slog.w(TAG, "Unable to write token file:", e);
Christopher Tate84725812010-02-04 15:52:40 -08001122 }
1123 }
1124
Dan Egnor87a02bc2009-06-17 02:30:10 -07001125 // Return the given transport
Christopher Tate91717492009-06-26 21:07:13 -07001126 private IBackupTransport getTransport(String transportName) {
1127 synchronized (mTransports) {
1128 IBackupTransport transport = mTransports.get(transportName);
1129 if (transport == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001130 Slog.w(TAG, "Requested unavailable transport: " + transportName);
Christopher Tate91717492009-06-26 21:07:13 -07001131 }
1132 return transport;
Christopher Tate8c850b72009-06-07 19:33:20 -07001133 }
Christopher Tate8c850b72009-06-07 19:33:20 -07001134 }
1135
Christopher Tatedf01dea2009-06-09 20:45:02 -07001136 // fire off a backup agent, blocking until it attaches or times out
1137 IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
1138 IBackupAgent agent = null;
1139 synchronized(mAgentConnectLock) {
1140 mConnecting = true;
1141 mConnectedAgent = null;
1142 try {
1143 if (mActivityManager.bindBackupAgent(app, mode)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001144 Slog.d(TAG, "awaiting agent for " + app);
Christopher Tatedf01dea2009-06-09 20:45:02 -07001145
1146 // success; wait for the agent to arrive
Christopher Tatec7b31e32009-06-10 15:49:30 -07001147 // only wait 10 seconds for the clear data to happen
1148 long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
1149 while (mConnecting && mConnectedAgent == null
1150 && (System.currentTimeMillis() < timeoutMark)) {
Christopher Tatedf01dea2009-06-09 20:45:02 -07001151 try {
Christopher Tatec7b31e32009-06-10 15:49:30 -07001152 mAgentConnectLock.wait(5000);
Christopher Tatedf01dea2009-06-09 20:45:02 -07001153 } catch (InterruptedException e) {
Christopher Tatec7b31e32009-06-10 15:49:30 -07001154 // just bail
Christopher Tatedf01dea2009-06-09 20:45:02 -07001155 return null;
1156 }
1157 }
1158
1159 // if we timed out with no connect, abort and move on
1160 if (mConnecting == true) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001161 Slog.w(TAG, "Timeout waiting for agent " + app);
Christopher Tatedf01dea2009-06-09 20:45:02 -07001162 return null;
1163 }
1164 agent = mConnectedAgent;
1165 }
1166 } catch (RemoteException e) {
1167 // can't happen
1168 }
1169 }
1170 return agent;
1171 }
1172
Christopher Tatec7b31e32009-06-10 15:49:30 -07001173 // clear an application's data, blocking until the operation completes or times out
1174 void clearApplicationDataSynchronous(String packageName) {
Christopher Tatef7c886b2009-06-26 15:34:09 -07001175 // Don't wipe packages marked allowClearUserData=false
1176 try {
1177 PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
1178 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001179 if (DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
Christopher Tatef7c886b2009-06-26 15:34:09 -07001180 + packageName);
1181 return;
1182 }
1183 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001184 Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
Christopher Tatef7c886b2009-06-26 15:34:09 -07001185 return;
1186 }
1187
Christopher Tatec7b31e32009-06-10 15:49:30 -07001188 ClearDataObserver observer = new ClearDataObserver();
1189
1190 synchronized(mClearDataLock) {
1191 mClearingData = true;
Christopher Tate9dfdac52009-08-06 14:57:53 -07001192 try {
1193 mActivityManager.clearApplicationUserData(packageName, observer);
1194 } catch (RemoteException e) {
1195 // can't happen because the activity manager is in this process
1196 }
Christopher Tatec7b31e32009-06-10 15:49:30 -07001197
1198 // only wait 10 seconds for the clear data to happen
1199 long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
1200 while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
1201 try {
1202 mClearDataLock.wait(5000);
1203 } catch (InterruptedException e) {
1204 // won't happen, but still.
1205 mClearingData = false;
1206 }
1207 }
1208 }
1209 }
1210
1211 class ClearDataObserver extends IPackageDataObserver.Stub {
Dan Egnor852f8e42009-09-30 11:20:45 -07001212 public void onRemoveCompleted(String packageName, boolean succeeded) {
Christopher Tatec7b31e32009-06-10 15:49:30 -07001213 synchronized(mClearDataLock) {
1214 mClearingData = false;
Christopher Tatef68eb502009-06-16 11:02:01 -07001215 mClearDataLock.notifyAll();
Christopher Tatec7b31e32009-06-10 15:49:30 -07001216 }
1217 }
1218 }
1219
Christopher Tate1bb69062010-02-19 17:02:12 -08001220 // Get the restore-set token for the best-available restore set for this package:
1221 // the active set if possible, else the ancestral one. Returns zero if none available.
1222 long getAvailableRestoreToken(String packageName) {
1223 long token = mAncestralToken;
1224 synchronized (mQueueLock) {
1225 if (mEverStoredApps.contains(packageName)) {
1226 token = mCurrentToken;
1227 }
1228 }
1229 return token;
1230 }
1231
Christopher Tate44a27902010-01-27 17:15:49 -08001232 // -----
1233 // Utility methods used by the asynchronous-with-timeout backup/restore operations
1234 boolean waitUntilOperationComplete(int token) {
1235 int finalState = OP_PENDING;
1236 synchronized (mCurrentOpLock) {
1237 try {
1238 while ((finalState = mCurrentOperations.get(token, OP_TIMEOUT)) == OP_PENDING) {
1239 try {
1240 mCurrentOpLock.wait();
1241 } catch (InterruptedException e) {}
1242 }
1243 } catch (IndexOutOfBoundsException e) {
1244 // the operation has been mysteriously cleared from our
1245 // bookkeeping -- consider this a success and ignore it.
1246 }
1247 }
1248 mBackupHandler.removeMessages(MSG_TIMEOUT);
Joe Onorato8a9b2202010-02-26 18:56:32 -08001249 if (DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
Christopher Tate1bb69062010-02-19 17:02:12 -08001250 + " complete: finalState=" + finalState);
Christopher Tate44a27902010-01-27 17:15:49 -08001251 return finalState == OP_ACKNOWLEDGED;
1252 }
1253
1254 void prepareOperationTimeout(int token, long interval) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001255 if (DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
Christopher Tate1bb69062010-02-19 17:02:12 -08001256 + " interval=" + interval);
Christopher Tate44a27902010-01-27 17:15:49 -08001257 mCurrentOperations.put(token, OP_PENDING);
1258 Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0);
1259 mBackupHandler.sendMessageDelayed(msg, interval);
1260 }
1261
Christopher Tate043dadc2009-06-02 16:11:00 -07001262 // ----- Back up a set of applications via a worker thread -----
1263
Christopher Tate44a27902010-01-27 17:15:49 -08001264 class PerformBackupTask implements Runnable {
Christopher Tate043dadc2009-06-02 16:11:00 -07001265 private static final String TAG = "PerformBackupThread";
Christopher Tateaa088442009-06-16 18:25:46 -07001266 IBackupTransport mTransport;
Christopher Tate043dadc2009-06-02 16:11:00 -07001267 ArrayList<BackupRequest> mQueue;
Christopher Tate5cb400b2009-06-25 16:03:14 -07001268 File mStateDir;
Christopher Tatecde87f42009-06-12 12:55:53 -07001269 File mJournal;
Christopher Tate043dadc2009-06-02 16:11:00 -07001270
Christopher Tate44a27902010-01-27 17:15:49 -08001271 public PerformBackupTask(IBackupTransport transport, ArrayList<BackupRequest> queue,
Christopher Tatecde87f42009-06-12 12:55:53 -07001272 File journal) {
Christopher Tateaa088442009-06-16 18:25:46 -07001273 mTransport = transport;
Christopher Tate043dadc2009-06-02 16:11:00 -07001274 mQueue = queue;
Christopher Tatecde87f42009-06-12 12:55:53 -07001275 mJournal = journal;
Christopher Tate5cb400b2009-06-25 16:03:14 -07001276
1277 try {
1278 mStateDir = new File(mBaseStateDir, transport.transportDirName());
1279 } catch (RemoteException e) {
1280 // can't happen; the transport is local
1281 }
Christopher Tate043dadc2009-06-02 16:11:00 -07001282 }
1283
Christopher Tate043dadc2009-06-02 16:11:00 -07001284 public void run() {
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001285 int status = BackupConstants.TRANSPORT_OK;
Dan Egnorbb9001c2009-07-27 12:20:13 -07001286 long startRealtime = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001287 if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
Christopher Tate043dadc2009-06-02 16:11:00 -07001288
Christopher Tate79588342009-06-30 16:11:49 -07001289 // Backups run at background priority
1290 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
1291
Christopher Tate043dadc2009-06-02 16:11:00 -07001292 try {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001293 EventLog.writeEvent(EventLogTags.BACKUP_START, mTransport.transportDirName());
Dan Egnor01445162009-09-21 17:04:05 -07001294
Dan Egnor852f8e42009-09-30 11:20:45 -07001295 // If we haven't stored package manager metadata yet, we must init the transport.
1296 File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
1297 if (status == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001298 Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
Dan Egnor852f8e42009-09-30 11:20:45 -07001299 resetBackupState(mStateDir); // Just to make sure.
Dan Egnor01445162009-09-21 17:04:05 -07001300 status = mTransport.initializeDevice();
Dan Egnor726247c2009-09-29 19:12:31 -07001301 if (status == BackupConstants.TRANSPORT_OK) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001302 EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
Dan Egnor726247c2009-09-29 19:12:31 -07001303 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001304 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
Joe Onorato8a9b2202010-02-26 18:56:32 -08001305 Slog.e(TAG, "Transport error in initializeDevice()");
Dan Egnor726247c2009-09-29 19:12:31 -07001306 }
Dan Egnor01445162009-09-21 17:04:05 -07001307 }
Dan Egnorbb9001c2009-07-27 12:20:13 -07001308
1309 // The package manager doesn't have a proper <application> etc, but since
1310 // it's running here in the system process we can just set up its agent
1311 // directly and use a synthetic BackupRequest. We always run this pass
1312 // because it's cheap and this way we guarantee that we don't get out of
1313 // step even if we're selecting among various transports at run time.
Dan Egnor01445162009-09-21 17:04:05 -07001314 if (status == BackupConstants.TRANSPORT_OK) {
1315 PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
1316 mPackageManager, allAgentPackages());
1317 BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
1318 pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
1319 status = processOneBackup(pmRequest,
1320 IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
1321 }
Christopher Tate90967f42009-09-20 15:28:33 -07001322
Dan Egnor01445162009-09-21 17:04:05 -07001323 if (status == BackupConstants.TRANSPORT_OK) {
1324 // Now run all the backups in our queue
1325 status = doQueuedBackups(mTransport);
1326 }
1327
1328 if (status == BackupConstants.TRANSPORT_OK) {
1329 // Tell the transport to finish everything it has buffered
1330 status = mTransport.finishBackup();
1331 if (status == BackupConstants.TRANSPORT_OK) {
1332 int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001333 EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, mQueue.size(), millis);
Dan Egnor01445162009-09-21 17:04:05 -07001334 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001335 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(finish)");
Joe Onorato8a9b2202010-02-26 18:56:32 -08001336 Slog.e(TAG, "Transport error in finishBackup()");
Dan Egnor01445162009-09-21 17:04:05 -07001337 }
1338 }
1339
Dan Egnor01445162009-09-21 17:04:05 -07001340 if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
Christopher Tated55e18a2009-09-21 10:12:59 -07001341 // The backend reports that our dataset has been wiped. We need to
1342 // reset all of our bookkeeping and instead run a new backup pass for
Christopher Tatec2af5d32010-02-02 15:18:58 -08001343 // everything.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001344 EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
Christopher Tated55e18a2009-09-21 10:12:59 -07001345 resetBackupState(mStateDir);
Dan Egnorbb9001c2009-07-27 12:20:13 -07001346 }
1347 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001348 Slog.e(TAG, "Error in backup thread", e);
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001349 status = BackupConstants.TRANSPORT_ERROR;
Dan Egnorbb9001c2009-07-27 12:20:13 -07001350 } finally {
Christopher Tate84725812010-02-04 15:52:40 -08001351 // If everything actually went through and this is the first time we've
1352 // done a backup, we can now record what the current backup dataset token
1353 // is.
Christopher Tate29505552010-06-24 15:58:01 -07001354 if ((mCurrentToken == 0) && (status == BackupConstants.TRANSPORT_OK)) {
Christopher Tate84725812010-02-04 15:52:40 -08001355 try {
1356 mCurrentToken = mTransport.getCurrentRestoreSet();
1357 } catch (RemoteException e) { /* cannot happen */ }
1358 writeRestoreTokens();
1359 }
1360
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001361 // If things went wrong, we need to re-stage the apps we had expected
1362 // to be backing up in this pass. This journals the package names in
1363 // the current active pending-backup file, not in the we are holding
1364 // here in mJournal.
1365 if (status != BackupConstants.TRANSPORT_OK) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001366 Slog.w(TAG, "Backup pass unsuccessful, restaging");
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001367 for (BackupRequest req : mQueue) {
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07001368 dataChangedImpl(req.appInfo.packageName);
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001369 }
Christopher Tate21ab6a52009-09-24 18:01:46 -07001370
1371 // We also want to reset the backup schedule based on whatever
1372 // the transport suggests by way of retry/backoff time.
1373 try {
1374 startBackupAlarmsLocked(mTransport.requestBackupTime());
1375 } catch (RemoteException e) { /* cannot happen */ }
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001376 }
1377
1378 // Either backup was successful, in which case we of course do not need
1379 // this pass's journal any more; or it failed, in which case we just
1380 // re-enqueued all of these packages in the current active journal.
1381 // Either way, we no longer need this pass's journal.
Dan Egnor852f8e42009-09-30 11:20:45 -07001382 if (mJournal != null && !mJournal.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001383 Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
Christopher Tateb03b3bb2009-09-22 11:14:17 -07001384 }
1385
Christopher Tatec2af5d32010-02-02 15:18:58 -08001386 // Only once we're entirely finished do we release the wakelock
Dan Egnor852f8e42009-09-30 11:20:45 -07001387 if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
Dan Egnor852f8e42009-09-30 11:20:45 -07001388 backupNow();
1389 }
1390
Dan Egnorbb9001c2009-07-27 12:20:13 -07001391 mWakelock.release();
Christopher Tatecde87f42009-06-12 12:55:53 -07001392 }
Christopher Tate043dadc2009-06-02 16:11:00 -07001393 }
1394
Dan Egnor01445162009-09-21 17:04:05 -07001395 private int doQueuedBackups(IBackupTransport transport) {
Christopher Tate043dadc2009-06-02 16:11:00 -07001396 for (BackupRequest request : mQueue) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001397 Slog.d(TAG, "starting agent for backup of " + request);
Christopher Tate043dadc2009-06-02 16:11:00 -07001398
Christopher Tatec28083a2010-12-14 16:16:44 -08001399 // Verify that the requested app exists; it might be something that
1400 // requested a backup but was then uninstalled. The request was
1401 // journalled and rather than tamper with the journal it's safer
1402 // to sanity-check here.
1403 try {
1404 mPackageManager.getPackageInfo(request.appInfo.packageName, 0);
1405 } catch (NameNotFoundException e) {
1406 Slog.d(TAG, "Package does not exist; skipping");
1407 continue;
1408 }
1409
Christopher Tate043dadc2009-06-02 16:11:00 -07001410 IBackupAgent agent = null;
1411 int mode = (request.fullBackup)
1412 ? IApplicationThread.BACKUP_MODE_FULL
1413 : IApplicationThread.BACKUP_MODE_INCREMENTAL;
1414 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001415 mWakelock.setWorkSource(new WorkSource(request.appInfo.uid));
Christopher Tatedf01dea2009-06-09 20:45:02 -07001416 agent = bindToAgentSynchronous(request.appInfo, mode);
1417 if (agent != null) {
Dan Egnor01445162009-09-21 17:04:05 -07001418 int result = processOneBackup(request, agent, transport);
1419 if (result != BackupConstants.TRANSPORT_OK) return result;
Christopher Tate043dadc2009-06-02 16:11:00 -07001420 }
Christopher Tate043dadc2009-06-02 16:11:00 -07001421 } catch (SecurityException ex) {
1422 // Try for the next one.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001423 Slog.d(TAG, "error in bind/backup", ex);
Dan Egnor01445162009-09-21 17:04:05 -07001424 } finally {
1425 try { // unbind even on timeout, just in case
1426 mActivityManager.unbindBackupAgent(request.appInfo);
1427 } catch (RemoteException e) {}
Christopher Tate043dadc2009-06-02 16:11:00 -07001428 }
1429 }
Dan Egnor01445162009-09-21 17:04:05 -07001430
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001431 mWakelock.setWorkSource(null);
1432
Dan Egnor01445162009-09-21 17:04:05 -07001433 return BackupConstants.TRANSPORT_OK;
Christopher Tate043dadc2009-06-02 16:11:00 -07001434 }
Christopher Tatec7b31e32009-06-10 15:49:30 -07001435
Dan Egnor01445162009-09-21 17:04:05 -07001436 private int processOneBackup(BackupRequest request, IBackupAgent agent,
1437 IBackupTransport transport) {
Christopher Tatec7b31e32009-06-10 15:49:30 -07001438 final String packageName = request.appInfo.packageName;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001439 if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName);
Christopher Tatec7b31e32009-06-10 15:49:30 -07001440
Dan Egnorbb9001c2009-07-27 12:20:13 -07001441 File savedStateName = new File(mStateDir, packageName);
1442 File backupDataName = new File(mDataDir, packageName + ".data");
1443 File newStateName = new File(mStateDir, packageName + ".new");
1444
1445 ParcelFileDescriptor savedState = null;
1446 ParcelFileDescriptor backupData = null;
1447 ParcelFileDescriptor newState = null;
1448
1449 PackageInfo packInfo;
Christopher Tate44a27902010-01-27 17:15:49 -08001450 int token = mTokenGenerator.nextInt();
Christopher Tatec7b31e32009-06-10 15:49:30 -07001451 try {
1452 // Look up the package info & signatures. This is first so that if it
1453 // throws an exception, there's no file setup yet that would need to
1454 // be unraveled.
Christopher Tateabce4e82009-06-18 18:35:32 -07001455 if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
1456 // The metadata 'package' is synthetic
1457 packInfo = new PackageInfo();
1458 packInfo.packageName = packageName;
1459 } else {
1460 packInfo = mPackageManager.getPackageInfo(packageName,
Christopher Tatec7b31e32009-06-10 15:49:30 -07001461 PackageManager.GET_SIGNATURES);
Christopher Tateabce4e82009-06-18 18:35:32 -07001462 }
Christopher Tatec7b31e32009-06-10 15:49:30 -07001463
Christopher Tatec7b31e32009-06-10 15:49:30 -07001464 // In a full backup, we pass a null ParcelFileDescriptor as
1465 // the saved-state "file"
Dan Egnorbb9001c2009-07-27 12:20:13 -07001466 if (!request.fullBackup) {
1467 savedState = ParcelFileDescriptor.open(savedStateName,
Christopher Tatec7b31e32009-06-10 15:49:30 -07001468 ParcelFileDescriptor.MODE_READ_ONLY |
Dan Egnorbb9001c2009-07-27 12:20:13 -07001469 ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
1470 }
Christopher Tatec7b31e32009-06-10 15:49:30 -07001471
Dan Egnorbb9001c2009-07-27 12:20:13 -07001472 backupData = ParcelFileDescriptor.open(backupDataName,
1473 ParcelFileDescriptor.MODE_READ_WRITE |
1474 ParcelFileDescriptor.MODE_CREATE |
1475 ParcelFileDescriptor.MODE_TRUNCATE);
Christopher Tatec7b31e32009-06-10 15:49:30 -07001476
Dan Egnorbb9001c2009-07-27 12:20:13 -07001477 newState = ParcelFileDescriptor.open(newStateName,
1478 ParcelFileDescriptor.MODE_READ_WRITE |
1479 ParcelFileDescriptor.MODE_CREATE |
1480 ParcelFileDescriptor.MODE_TRUNCATE);
Christopher Tatec7b31e32009-06-10 15:49:30 -07001481
Christopher Tate44a27902010-01-27 17:15:49 -08001482 // Initiate the target's backup pass
1483 prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
1484 agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
1485 boolean success = waitUntilOperationComplete(token);
1486
1487 if (!success) {
1488 // timeout -- bail out into the failed-transaction logic
1489 throw new RuntimeException("Backup timeout");
1490 }
1491
Dan Egnorbb9001c2009-07-27 12:20:13 -07001492 logBackupComplete(packageName);
Joe Onorato8a9b2202010-02-26 18:56:32 -08001493 if (DEBUG) Slog.v(TAG, "doBackup() success");
Christopher Tatec7b31e32009-06-10 15:49:30 -07001494 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001495 Slog.e(TAG, "Error backing up " + packageName, e);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001496 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString());
Dan Egnorbb9001c2009-07-27 12:20:13 -07001497 backupDataName.delete();
1498 newStateName.delete();
Christopher Tated55e18a2009-09-21 10:12:59 -07001499 return BackupConstants.TRANSPORT_ERROR;
Dan Egnorbb9001c2009-07-27 12:20:13 -07001500 } finally {
1501 try { if (savedState != null) savedState.close(); } catch (IOException e) {}
1502 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
1503 try { if (newState != null) newState.close(); } catch (IOException e) {}
1504 savedState = backupData = newState = null;
Christopher Tate44a27902010-01-27 17:15:49 -08001505 synchronized (mCurrentOpLock) {
1506 mCurrentOperations.clear();
1507 }
Dan Egnorbb9001c2009-07-27 12:20:13 -07001508 }
1509
1510 // Now propagate the newly-backed-up data to the transport
Dan Egnor01445162009-09-21 17:04:05 -07001511 int result = BackupConstants.TRANSPORT_OK;
Dan Egnorbb9001c2009-07-27 12:20:13 -07001512 try {
1513 int size = (int) backupDataName.length();
1514 if (size > 0) {
Dan Egnor01445162009-09-21 17:04:05 -07001515 if (result == BackupConstants.TRANSPORT_OK) {
1516 backupData = ParcelFileDescriptor.open(backupDataName,
1517 ParcelFileDescriptor.MODE_READ_ONLY);
1518 result = transport.performBackup(packInfo, backupData);
1519 }
Dan Egnorbb9001c2009-07-27 12:20:13 -07001520
Dan Egnor83861e72009-09-17 16:17:55 -07001521 // TODO - We call finishBackup() for each application backed up, because
1522 // we need to know now whether it succeeded or failed. Instead, we should
1523 // hold off on finishBackup() until the end, which implies holding off on
1524 // renaming *all* the output state files (see below) until that happens.
1525
Dan Egnor01445162009-09-21 17:04:05 -07001526 if (result == BackupConstants.TRANSPORT_OK) {
1527 result = transport.finishBackup();
Dan Egnor83861e72009-09-17 16:17:55 -07001528 }
Dan Egnorbb9001c2009-07-27 12:20:13 -07001529 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001530 if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
Dan Egnorbb9001c2009-07-27 12:20:13 -07001531 }
1532
1533 // After successful transport, delete the now-stale data
1534 // and juggle the files so that next time we supply the agent
1535 // with the new state file it just created.
Dan Egnor01445162009-09-21 17:04:05 -07001536 if (result == BackupConstants.TRANSPORT_OK) {
1537 backupDataName.delete();
1538 newStateName.renameTo(savedStateName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001539 EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, packageName, size);
Dan Egnor01445162009-09-21 17:04:05 -07001540 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001541 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
Dan Egnor01445162009-09-21 17:04:05 -07001542 }
Dan Egnorbb9001c2009-07-27 12:20:13 -07001543 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001544 Slog.e(TAG, "Transport error backing up " + packageName, e);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001545 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
Dan Egnor01445162009-09-21 17:04:05 -07001546 result = BackupConstants.TRANSPORT_ERROR;
Dan Egnorbb9001c2009-07-27 12:20:13 -07001547 } finally {
1548 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
Christopher Tatec7b31e32009-06-10 15:49:30 -07001549 }
Christopher Tated55e18a2009-09-21 10:12:59 -07001550
Dan Egnor01445162009-09-21 17:04:05 -07001551 return result;
Christopher Tatec7b31e32009-06-10 15:49:30 -07001552 }
Christopher Tate043dadc2009-06-02 16:11:00 -07001553 }
1554
Christopher Tatedf01dea2009-06-09 20:45:02 -07001555
1556 // ----- Restore handling -----
1557
Christopher Tate78dd4a72009-11-04 11:49:08 -08001558 private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
1559 // If the target resides on the system partition, we allow it to restore
1560 // data from the like-named package in a restore set even if the signatures
1561 // do not match. (Unlike general applications, those flashed to the system
1562 // partition will be signed with the device's platform certificate, so on
1563 // different phones the same system app will have different signatures.)
1564 if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001565 if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
Christopher Tate78dd4a72009-11-04 11:49:08 -08001566 return true;
1567 }
1568
Christopher Tate20efdf6b2009-06-18 19:41:36 -07001569 // Allow unsigned apps, but not signed on one device and unsigned on the other
1570 // !!! TODO: is this the right policy?
Christopher Tate78dd4a72009-11-04 11:49:08 -08001571 Signature[] deviceSigs = target.signatures;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001572 if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
Christopher Tate6aa41f42009-06-19 14:14:22 -07001573 + " device=" + deviceSigs);
Christopher Tate20efdf6b2009-06-18 19:41:36 -07001574 if ((storedSigs == null || storedSigs.length == 0)
1575 && (deviceSigs == null || deviceSigs.length == 0)) {
1576 return true;
1577 }
1578 if (storedSigs == null || deviceSigs == null) {
1579 return false;
1580 }
1581
Christopher Tateabce4e82009-06-18 18:35:32 -07001582 // !!! TODO: this demands that every stored signature match one
1583 // that is present on device, and does not demand the converse.
1584 // Is this this right policy?
1585 int nStored = storedSigs.length;
1586 int nDevice = deviceSigs.length;
1587
1588 for (int i=0; i < nStored; i++) {
1589 boolean match = false;
1590 for (int j=0; j < nDevice; j++) {
1591 if (storedSigs[i].equals(deviceSigs[j])) {
1592 match = true;
1593 break;
1594 }
1595 }
1596 if (!match) {
1597 return false;
1598 }
1599 }
1600 return true;
1601 }
1602
Christopher Tate44a27902010-01-27 17:15:49 -08001603 class PerformRestoreTask implements Runnable {
Christopher Tatedf01dea2009-06-09 20:45:02 -07001604 private IBackupTransport mTransport;
Christopher Tate7d562ec2009-06-25 18:03:43 -07001605 private IRestoreObserver mObserver;
Dan Egnor156411d2009-06-26 13:20:02 -07001606 private long mToken;
Christopher Tate84725812010-02-04 15:52:40 -08001607 private PackageInfo mTargetPackage;
Christopher Tate5cb400b2009-06-25 16:03:14 -07001608 private File mStateDir;
Christopher Tate1bb69062010-02-19 17:02:12 -08001609 private int mPmToken;
Chris Tate249345b2010-10-29 12:57:04 -07001610 private boolean mNeedFullBackup;
Christopher Tatedf01dea2009-06-09 20:45:02 -07001611
Christopher Tate5cbbf562009-06-22 16:44:51 -07001612 class RestoreRequest {
1613 public PackageInfo app;
1614 public int storedAppVersion;
1615
1616 RestoreRequest(PackageInfo _app, int _version) {
1617 app = _app;
1618 storedAppVersion = _version;
1619 }
1620 }
1621
Christopher Tate44a27902010-01-27 17:15:49 -08001622 PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
Chris Tate249345b2010-10-29 12:57:04 -07001623 long restoreSetToken, PackageInfo targetPackage, int pmToken,
1624 boolean needFullBackup) {
Christopher Tatedf01dea2009-06-09 20:45:02 -07001625 mTransport = transport;
Christopher Tate7d562ec2009-06-25 18:03:43 -07001626 mObserver = observer;
Christopher Tate9bbc21a2009-06-10 20:23:25 -07001627 mToken = restoreSetToken;
Christopher Tate84725812010-02-04 15:52:40 -08001628 mTargetPackage = targetPackage;
Christopher Tate1bb69062010-02-19 17:02:12 -08001629 mPmToken = pmToken;
Chris Tate249345b2010-10-29 12:57:04 -07001630 mNeedFullBackup = needFullBackup;
Christopher Tate5cb400b2009-06-25 16:03:14 -07001631
1632 try {
1633 mStateDir = new File(mBaseStateDir, transport.transportDirName());
1634 } catch (RemoteException e) {
1635 // can't happen; the transport is local
1636 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001637 }
1638
Christopher Tatedf01dea2009-06-09 20:45:02 -07001639 public void run() {
Dan Egnorbb9001c2009-07-27 12:20:13 -07001640 long startRealtime = SystemClock.elapsedRealtime();
Joe Onorato8a9b2202010-02-26 18:56:32 -08001641 if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
Christopher Tate84725812010-02-04 15:52:40 -08001642 + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
Christopher Tate1bb69062010-02-19 17:02:12 -08001643 + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
Christopher Tatedf01dea2009-06-09 20:45:02 -07001644
Christopher Tateb49ceb32010-02-08 16:22:24 -08001645 PackageManagerBackupAgent pmAgent = null;
Christopher Tate7d562ec2009-06-25 18:03:43 -07001646 int error = -1; // assume error
1647
Dan Egnorefe52642009-06-24 00:16:33 -07001648 // build the set of apps to restore
Christopher Tatedf01dea2009-06-09 20:45:02 -07001649 try {
Dan Egnorbb9001c2009-07-27 12:20:13 -07001650 // TODO: Log this before getAvailableRestoreSets, somehow
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001651 EventLog.writeEvent(EventLogTags.RESTORE_START, mTransport.transportDirName(), mToken);
Christopher Tateabce4e82009-06-18 18:35:32 -07001652
Dan Egnorefe52642009-06-24 00:16:33 -07001653 // Get the list of all packages which have backup enabled.
1654 // (Include the Package Manager metadata pseudo-package first.)
1655 ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
1656 PackageInfo omPackage = new PackageInfo();
1657 omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
1658 restorePackages.add(omPackage);
Christopher Tatedf01dea2009-06-09 20:45:02 -07001659
Dan Egnorefe52642009-06-24 00:16:33 -07001660 List<PackageInfo> agentPackages = allAgentPackages();
Christopher Tate84725812010-02-04 15:52:40 -08001661 if (mTargetPackage == null) {
1662 restorePackages.addAll(agentPackages);
1663 } else {
1664 // Just one package to attempt restore of
1665 restorePackages.add(mTargetPackage);
1666 }
Dan Egnorefe52642009-06-24 00:16:33 -07001667
Christopher Tate7d562ec2009-06-25 18:03:43 -07001668 // let the observer know that we're running
1669 if (mObserver != null) {
1670 try {
1671 // !!! TODO: get an actual count from the transport after
1672 // its startRestore() runs?
1673 mObserver.restoreStarting(restorePackages.size());
1674 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001675 Slog.d(TAG, "Restore observer died at restoreStarting");
Christopher Tate7d562ec2009-06-25 18:03:43 -07001676 mObserver = null;
1677 }
1678 }
1679
Dan Egnor01445162009-09-21 17:04:05 -07001680 if (mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0])) !=
1681 BackupConstants.TRANSPORT_OK) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001682 Slog.e(TAG, "Error starting restore operation");
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001683 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
Dan Egnorefe52642009-06-24 00:16:33 -07001684 return;
1685 }
1686
1687 String packageName = mTransport.nextRestorePackage();
1688 if (packageName == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001689 Slog.e(TAG, "Error getting first restore package");
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001690 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
Dan Egnorefe52642009-06-24 00:16:33 -07001691 return;
1692 } else if (packageName.equals("")) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001693 Slog.i(TAG, "No restore data available");
Dan Egnorbb9001c2009-07-27 12:20:13 -07001694 int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001695 EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, 0, millis);
Dan Egnorefe52642009-06-24 00:16:33 -07001696 return;
1697 } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001698 Slog.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
Dan Egnorefe52642009-06-24 00:16:33 -07001699 + "\", found only \"" + packageName + "\"");
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001700 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
Dan Egnorbb9001c2009-07-27 12:20:13 -07001701 "Package manager data missing");
Dan Egnorefe52642009-06-24 00:16:33 -07001702 return;
1703 }
1704
1705 // Pull the Package Manager metadata from the restore set first
Christopher Tateb49ceb32010-02-08 16:22:24 -08001706 pmAgent = new PackageManagerBackupAgent(
Dan Egnorefe52642009-06-24 00:16:33 -07001707 mPackageManager, agentPackages);
Chris Tate249345b2010-10-29 12:57:04 -07001708 processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()),
1709 mNeedFullBackup);
Dan Egnorefe52642009-06-24 00:16:33 -07001710
Christopher Tate8c032472009-07-02 14:28:47 -07001711 // Verify that the backup set includes metadata. If not, we can't do
1712 // signature/version verification etc, so we simply do not proceed with
1713 // the restore operation.
Christopher Tate3d7cd132009-07-07 14:23:07 -07001714 if (!pmAgent.hasMetadata()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001715 Slog.e(TAG, "No restore metadata available, so not restoring settings");
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001716 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
Dan Egnorbb9001c2009-07-27 12:20:13 -07001717 "Package manager restore metadata missing");
Christopher Tate8c032472009-07-02 14:28:47 -07001718 return;
1719 }
1720
Christopher Tate7d562ec2009-06-25 18:03:43 -07001721 int count = 0;
Dan Egnorefe52642009-06-24 00:16:33 -07001722 for (;;) {
1723 packageName = mTransport.nextRestorePackage();
Dan Egnorbb9001c2009-07-27 12:20:13 -07001724
Dan Egnorefe52642009-06-24 00:16:33 -07001725 if (packageName == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001726 Slog.e(TAG, "Error getting next restore package");
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001727 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
Dan Egnorefe52642009-06-24 00:16:33 -07001728 return;
1729 } else if (packageName.equals("")) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001730 if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
Dan Egnorefe52642009-06-24 00:16:33 -07001731 break;
Christopher Tatedf01dea2009-06-09 20:45:02 -07001732 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001733
Christopher Tate7d562ec2009-06-25 18:03:43 -07001734 if (mObserver != null) {
Christopher Tate7d562ec2009-06-25 18:03:43 -07001735 try {
Christopher Tate9c3cee92010-03-25 16:06:43 -07001736 mObserver.onUpdate(count, packageName);
Christopher Tate7d562ec2009-06-25 18:03:43 -07001737 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001738 Slog.d(TAG, "Restore observer died in onUpdate");
Christopher Tate7d562ec2009-06-25 18:03:43 -07001739 mObserver = null;
1740 }
1741 }
1742
Dan Egnorefe52642009-06-24 00:16:33 -07001743 Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
1744 if (metaInfo == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001745 Slog.e(TAG, "Missing metadata for " + packageName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001746 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
Dan Egnorbb9001c2009-07-27 12:20:13 -07001747 "Package metadata missing");
Dan Egnorefe52642009-06-24 00:16:33 -07001748 continue;
1749 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001750
Dan Egnorbb9001c2009-07-27 12:20:13 -07001751 PackageInfo packageInfo;
1752 try {
1753 int flags = PackageManager.GET_SIGNATURES;
1754 packageInfo = mPackageManager.getPackageInfo(packageName, flags);
1755 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001756 Slog.e(TAG, "Invalid package restoring data", e);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001757 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
Dan Egnorbb9001c2009-07-27 12:20:13 -07001758 "Package missing on device");
1759 continue;
1760 }
1761
Dan Egnorefe52642009-06-24 00:16:33 -07001762 if (metaInfo.versionCode > packageInfo.versionCode) {
Christopher Tate3dda5182010-02-24 16:06:18 -08001763 // Data is from a "newer" version of the app than we have currently
1764 // installed. If the app has not declared that it is prepared to
1765 // handle this case, we do not attempt the restore.
1766 if ((packageInfo.applicationInfo.flags
1767 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
1768 String message = "Version " + metaInfo.versionCode
1769 + " > installed version " + packageInfo.versionCode;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001770 Slog.w(TAG, "Package " + packageName + ": " + message);
Christopher Tate3dda5182010-02-24 16:06:18 -08001771 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
1772 packageName, message);
1773 continue;
1774 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001775 if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
Christopher Tate3dda5182010-02-24 16:06:18 -08001776 + " > installed " + packageInfo.versionCode
1777 + " but restoreAnyVersion");
1778 }
Dan Egnorefe52642009-06-24 00:16:33 -07001779 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001780
Christopher Tate78dd4a72009-11-04 11:49:08 -08001781 if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001782 Slog.w(TAG, "Signature mismatch restoring " + packageName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001783 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
Dan Egnorbb9001c2009-07-27 12:20:13 -07001784 "Signature mismatch");
Dan Egnorefe52642009-06-24 00:16:33 -07001785 continue;
1786 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001787
Joe Onorato8a9b2202010-02-26 18:56:32 -08001788 if (DEBUG) Slog.v(TAG, "Package " + packageName
Dan Egnorefe52642009-06-24 00:16:33 -07001789 + " restore version [" + metaInfo.versionCode
1790 + "] is compatible with installed version ["
1791 + packageInfo.versionCode + "]");
Christopher Tatec7b31e32009-06-10 15:49:30 -07001792
Christopher Tate3de55bc2010-03-12 17:28:08 -08001793 // Then set up and bind the agent
Dan Egnorefe52642009-06-24 00:16:33 -07001794 IBackupAgent agent = bindToAgentSynchronous(
1795 packageInfo.applicationInfo,
Christopher Tate3de55bc2010-03-12 17:28:08 -08001796 IApplicationThread.BACKUP_MODE_INCREMENTAL);
Dan Egnorefe52642009-06-24 00:16:33 -07001797 if (agent == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001798 Slog.w(TAG, "Can't find backup agent for " + packageName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001799 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
Dan Egnorbb9001c2009-07-27 12:20:13 -07001800 "Restore agent missing");
Dan Egnorefe52642009-06-24 00:16:33 -07001801 continue;
Christopher Tatedf01dea2009-06-09 20:45:02 -07001802 }
1803
Christopher Tate5e1ab332009-09-01 20:32:49 -07001804 // And then finally run the restore on this agent
Dan Egnorefe52642009-06-24 00:16:33 -07001805 try {
Chris Tate249345b2010-10-29 12:57:04 -07001806 processOneRestore(packageInfo, metaInfo.versionCode, agent,
1807 mNeedFullBackup);
Dan Egnorbb9001c2009-07-27 12:20:13 -07001808 ++count;
Dan Egnorefe52642009-06-24 00:16:33 -07001809 } finally {
Christopher Tate5e1ab332009-09-01 20:32:49 -07001810 // unbind and tidy up even on timeout or failure, just in case
Dan Egnorefe52642009-06-24 00:16:33 -07001811 mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
Christopher Tate5e1ab332009-09-01 20:32:49 -07001812
1813 // The agent was probably running with a stub Application object,
1814 // which isn't a valid run mode for the main app logic. Shut
1815 // down the app so that next time it's launched, it gets the
Christopher Tate3dda5182010-02-24 16:06:18 -08001816 // usual full initialization. Note that this is only done for
1817 // full-system restores: when a single app has requested a restore,
1818 // it is explicitly not killed following that operation.
1819 if (mTargetPackage == null && (packageInfo.applicationInfo.flags
Christopher Tate5e1ab332009-09-01 20:32:49 -07001820 & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001821 if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
Christopher Tate5e1ab332009-09-01 20:32:49 -07001822 + packageInfo.applicationInfo.processName);
1823 mActivityManager.killApplicationProcess(
1824 packageInfo.applicationInfo.processName,
1825 packageInfo.applicationInfo.uid);
1826 }
Dan Egnorefe52642009-06-24 00:16:33 -07001827 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001828 }
Christopher Tate7d562ec2009-06-25 18:03:43 -07001829
1830 // if we get this far, report success to the observer
1831 error = 0;
Dan Egnorbb9001c2009-07-27 12:20:13 -07001832 int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001833 EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, count, millis);
Dan Egnorbb9001c2009-07-27 12:20:13 -07001834 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001835 Slog.e(TAG, "Error in restore thread", e);
Dan Egnorefe52642009-06-24 00:16:33 -07001836 } finally {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001837 if (DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
Dan Egnorbb9001c2009-07-27 12:20:13 -07001838
Dan Egnorefe52642009-06-24 00:16:33 -07001839 try {
1840 mTransport.finishRestore();
1841 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001842 Slog.e(TAG, "Error finishing restore", e);
Dan Egnorefe52642009-06-24 00:16:33 -07001843 }
Christopher Tate7d562ec2009-06-25 18:03:43 -07001844
1845 if (mObserver != null) {
1846 try {
1847 mObserver.restoreFinished(error);
1848 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001849 Slog.d(TAG, "Restore observer died at restoreFinished");
Christopher Tate7d562ec2009-06-25 18:03:43 -07001850 }
1851 }
Christopher Tateb6787f22009-07-02 17:40:45 -07001852
Christopher Tate84725812010-02-04 15:52:40 -08001853 // If this was a restoreAll operation, record that this was our
Christopher Tateb49ceb32010-02-08 16:22:24 -08001854 // ancestral dataset, as well as the set of apps that are possibly
1855 // restoreable from the dataset
1856 if (mTargetPackage == null && pmAgent != null) {
1857 mAncestralPackages = pmAgent.getRestoredPackages();
Christopher Tate84725812010-02-04 15:52:40 -08001858 mAncestralToken = mToken;
1859 writeRestoreTokens();
1860 }
1861
Christopher Tate1bb69062010-02-19 17:02:12 -08001862 // We must under all circumstances tell the Package Manager to
1863 // proceed with install notifications if it's waiting for us.
1864 if (mPmToken > 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001865 if (DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
Christopher Tate1bb69062010-02-19 17:02:12 -08001866 try {
1867 mPackageManagerBinder.finishPackageInstall(mPmToken);
1868 } catch (RemoteException e) { /* can't happen */ }
1869 }
1870
Christopher Tate73a3cb32010-12-13 18:27:26 -08001871 // Furthermore we need to reset the session timeout clock
1872 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
1873 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
1874 TIMEOUT_RESTORE_INTERVAL);
1875
Christopher Tateb6787f22009-07-02 17:40:45 -07001876 // done; we can finally release the wakelock
1877 mWakelock.release();
Christopher Tatedf01dea2009-06-09 20:45:02 -07001878 }
1879 }
1880
Dan Egnorefe52642009-06-24 00:16:33 -07001881 // Do the guts of a restore of one application, using mTransport.getRestoreData().
Chris Tate249345b2010-10-29 12:57:04 -07001882 void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
1883 boolean needFullBackup) {
Christopher Tatedf01dea2009-06-09 20:45:02 -07001884 // !!! TODO: actually run the restore through mTransport
Christopher Tatec7b31e32009-06-10 15:49:30 -07001885 final String packageName = app.packageName;
1886
Joe Onorato8a9b2202010-02-26 18:56:32 -08001887 if (DEBUG) Slog.d(TAG, "processOneRestore packageName=" + packageName);
Joe Onorato9a5e3e12009-07-01 21:04:03 -04001888
Christopher Tatec7b31e32009-06-10 15:49:30 -07001889 // !!! TODO: get the dirs from the transport
1890 File backupDataName = new File(mDataDir, packageName + ".restore");
Dan Egnorbb9001c2009-07-27 12:20:13 -07001891 File newStateName = new File(mStateDir, packageName + ".new");
1892 File savedStateName = new File(mStateDir, packageName);
Christopher Tatec7b31e32009-06-10 15:49:30 -07001893
Dan Egnorbb9001c2009-07-27 12:20:13 -07001894 ParcelFileDescriptor backupData = null;
1895 ParcelFileDescriptor newState = null;
1896
Christopher Tate44a27902010-01-27 17:15:49 -08001897 int token = mTokenGenerator.nextInt();
Dan Egnorbb9001c2009-07-27 12:20:13 -07001898 try {
Christopher Tatec7b31e32009-06-10 15:49:30 -07001899 // Run the transport's restore pass
Dan Egnorbb9001c2009-07-27 12:20:13 -07001900 backupData = ParcelFileDescriptor.open(backupDataName,
1901 ParcelFileDescriptor.MODE_READ_WRITE |
1902 ParcelFileDescriptor.MODE_CREATE |
1903 ParcelFileDescriptor.MODE_TRUNCATE);
1904
Dan Egnor01445162009-09-21 17:04:05 -07001905 if (mTransport.getRestoreData(backupData) != BackupConstants.TRANSPORT_OK) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001906 Slog.e(TAG, "Error getting restore data for " + packageName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001907 EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
Dan Egnorbb9001c2009-07-27 12:20:13 -07001908 return;
Christopher Tatec7b31e32009-06-10 15:49:30 -07001909 }
1910
1911 // Okay, we have the data. Now have the agent do the restore.
Dan Egnorbb9001c2009-07-27 12:20:13 -07001912 backupData.close();
Christopher Tatec7b31e32009-06-10 15:49:30 -07001913 backupData = ParcelFileDescriptor.open(backupDataName,
1914 ParcelFileDescriptor.MODE_READ_ONLY);
1915
Dan Egnorbb9001c2009-07-27 12:20:13 -07001916 newState = ParcelFileDescriptor.open(newStateName,
1917 ParcelFileDescriptor.MODE_READ_WRITE |
1918 ParcelFileDescriptor.MODE_CREATE |
1919 ParcelFileDescriptor.MODE_TRUNCATE);
1920
Christopher Tate44a27902010-01-27 17:15:49 -08001921 // Kick off the restore, checking for hung agents
1922 prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL);
1923 agent.doRestore(backupData, appVersionCode, newState, token, mBackupManagerBinder);
1924 boolean success = waitUntilOperationComplete(token);
1925
1926 if (!success) {
1927 throw new RuntimeException("restore timeout");
1928 }
Christopher Tatec7b31e32009-06-10 15:49:30 -07001929
1930 // if everything went okay, remember the recorded state now
Christopher Tate90967f42009-09-20 15:28:33 -07001931 //
1932 // !!! TODO: the restored data should be migrated on the server
1933 // side into the current dataset. In that case the new state file
1934 // we just created would reflect the data already extant in the
1935 // backend, so there'd be nothing more to do. Until that happens,
1936 // however, we need to make sure that we record the data to the
1937 // current backend dataset. (Yes, this means shipping the data over
1938 // the wire in both directions. That's bad, but consistency comes
1939 // first, then efficiency.) Once we introduce server-side data
1940 // migration to the newly-restored device's dataset, we will change
1941 // the following from a discard of the newly-written state to the
1942 // "correct" operation of renaming into the canonical state blob.
1943 newStateName.delete(); // TODO: remove; see above comment
1944 //newStateName.renameTo(savedStateName); // TODO: replace with this
1945
Dan Egnorbb9001c2009-07-27 12:20:13 -07001946 int size = (int) backupDataName.length();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001947 EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, packageName, size);
Christopher Tatec7b31e32009-06-10 15:49:30 -07001948 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001949 Slog.e(TAG, "Error restoring data for " + packageName, e);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001950 EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, e.toString());
Dan Egnorbb9001c2009-07-27 12:20:13 -07001951
Christopher Tate96733042009-07-20 14:49:13 -07001952 // If the agent fails restore, it might have put the app's data
1953 // into an incoherent state. For consistency we wipe its data
1954 // again in this case before propagating the exception
Christopher Tate96733042009-07-20 14:49:13 -07001955 clearApplicationDataSynchronous(packageName);
Christopher Tate1531dc82009-07-24 16:37:43 -07001956 } finally {
1957 backupDataName.delete();
Dan Egnorbb9001c2009-07-27 12:20:13 -07001958 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
1959 try { if (newState != null) newState.close(); } catch (IOException e) {}
1960 backupData = newState = null;
Christopher Tate44a27902010-01-27 17:15:49 -08001961 mCurrentOperations.delete(token);
Chris Tate249345b2010-10-29 12:57:04 -07001962
1963 // If we know a priori that we'll need to perform a full post-restore backup
1964 // pass, clear the new state file data. This means we're discarding work that
1965 // was just done by the app's agent, but this way the agent doesn't need to
1966 // take any special action based on global device state.
1967 if (needFullBackup) {
1968 newStateName.delete();
1969 }
Christopher Tatec7b31e32009-06-10 15:49:30 -07001970 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07001971 }
1972 }
1973
Christopher Tate44a27902010-01-27 17:15:49 -08001974 class PerformClearTask implements Runnable {
Christopher Tateee0e78a2009-07-02 11:17:03 -07001975 IBackupTransport mTransport;
1976 PackageInfo mPackage;
1977
Christopher Tate44a27902010-01-27 17:15:49 -08001978 PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
Christopher Tateee0e78a2009-07-02 11:17:03 -07001979 mTransport = transport;
1980 mPackage = packageInfo;
1981 }
1982
Christopher Tateee0e78a2009-07-02 11:17:03 -07001983 public void run() {
1984 try {
1985 // Clear the on-device backup state to ensure a full backup next time
1986 File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
1987 File stateFile = new File(stateDir, mPackage.packageName);
1988 stateFile.delete();
1989
1990 // Tell the transport to remove all the persistent storage for the app
Christopher Tate13f4a642009-09-30 20:06:45 -07001991 // TODO - need to handle failures
Christopher Tateee0e78a2009-07-02 11:17:03 -07001992 mTransport.clearBackupData(mPackage);
1993 } catch (RemoteException e) {
1994 // can't happen; the transport is local
1995 } finally {
1996 try {
Christopher Tate13f4a642009-09-30 20:06:45 -07001997 // TODO - need to handle failures
Christopher Tateee0e78a2009-07-02 11:17:03 -07001998 mTransport.finishBackup();
1999 } catch (RemoteException e) {
2000 // can't happen; the transport is local
2001 }
Christopher Tateb6787f22009-07-02 17:40:45 -07002002
2003 // Last but not least, release the cpu
2004 mWakelock.release();
Christopher Tateee0e78a2009-07-02 11:17:03 -07002005 }
2006 }
2007 }
2008
Christopher Tate44a27902010-01-27 17:15:49 -08002009 class PerformInitializeTask implements Runnable {
Christopher Tate4cc86e12009-09-21 19:36:51 -07002010 HashSet<String> mQueue;
2011
Christopher Tate44a27902010-01-27 17:15:49 -08002012 PerformInitializeTask(HashSet<String> transportNames) {
Christopher Tate4cc86e12009-09-21 19:36:51 -07002013 mQueue = transportNames;
2014 }
2015
Christopher Tate4cc86e12009-09-21 19:36:51 -07002016 public void run() {
Christopher Tate4cc86e12009-09-21 19:36:51 -07002017 try {
2018 for (String transportName : mQueue) {
2019 IBackupTransport transport = getTransport(transportName);
2020 if (transport == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002021 Slog.e(TAG, "Requested init for " + transportName + " but not found");
Christopher Tate4cc86e12009-09-21 19:36:51 -07002022 continue;
2023 }
2024
Joe Onorato8a9b2202010-02-26 18:56:32 -08002025 Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002026 EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
Dan Egnor726247c2009-09-29 19:12:31 -07002027 long startRealtime = SystemClock.elapsedRealtime();
2028 int status = transport.initializeDevice();
Christopher Tate4cc86e12009-09-21 19:36:51 -07002029
Christopher Tate4cc86e12009-09-21 19:36:51 -07002030 if (status == BackupConstants.TRANSPORT_OK) {
2031 status = transport.finishBackup();
2032 }
2033
2034 // Okay, the wipe really happened. Clean up our local bookkeeping.
2035 if (status == BackupConstants.TRANSPORT_OK) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002036 Slog.i(TAG, "Device init successful");
Dan Egnor726247c2009-09-29 19:12:31 -07002037 int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002038 EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
Dan Egnor726247c2009-09-29 19:12:31 -07002039 resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002040 EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
Christopher Tate4cc86e12009-09-21 19:36:51 -07002041 synchronized (mQueueLock) {
2042 recordInitPendingLocked(false, transportName);
2043 }
Dan Egnor726247c2009-09-29 19:12:31 -07002044 } else {
2045 // If this didn't work, requeue this one and try again
2046 // after a suitable interval
Joe Onorato8a9b2202010-02-26 18:56:32 -08002047 Slog.e(TAG, "Transport error in initializeDevice()");
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002048 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
Christopher Tate4cc86e12009-09-21 19:36:51 -07002049 synchronized (mQueueLock) {
2050 recordInitPendingLocked(true, transportName);
2051 }
2052 // do this via another alarm to make sure of the wakelock states
2053 long delay = transport.requestBackupTime();
Joe Onorato8a9b2202010-02-26 18:56:32 -08002054 if (DEBUG) Slog.w(TAG, "init failed on "
Christopher Tate4cc86e12009-09-21 19:36:51 -07002055 + transportName + " resched in " + delay);
2056 mAlarmManager.set(AlarmManager.RTC_WAKEUP,
2057 System.currentTimeMillis() + delay, mRunInitIntent);
Christopher Tate4cc86e12009-09-21 19:36:51 -07002058 }
Christopher Tate4cc86e12009-09-21 19:36:51 -07002059 }
2060 } catch (RemoteException e) {
2061 // can't happen; the transports are local
2062 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002063 Slog.e(TAG, "Unexpected error performing init", e);
Christopher Tate4cc86e12009-09-21 19:36:51 -07002064 } finally {
Christopher Tatec2af5d32010-02-02 15:18:58 -08002065 // Done; release the wakelock
Christopher Tate4cc86e12009-09-21 19:36:51 -07002066 mWakelock.release();
2067 }
2068 }
2069 }
2070
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002071 private void dataChangedImpl(String packageName) {
2072 HashSet<ApplicationInfo> targets = dataChangedTargets(packageName);
2073 dataChangedImpl(packageName, targets);
2074 }
Christopher Tatedf01dea2009-06-09 20:45:02 -07002075
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002076 private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> targets) {
Christopher Tate487529a2009-04-29 14:03:25 -07002077 // Record that we need a backup pass for the caller. Since multiple callers
2078 // may share a uid, we need to note all candidates within that uid and schedule
2079 // a backup pass for each of them.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002080 EventLog.writeEvent(EventLogTags.BACKUP_DATA_CHANGED, packageName);
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002081
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002082 if (targets == null) {
2083 Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
2084 + " uid=" + Binder.getCallingUid());
2085 return;
2086 }
2087
2088 synchronized (mQueueLock) {
2089 // Note that this client has made data changes that need to be backed up
2090 for (ApplicationInfo app : targets) {
2091 // validate the caller-supplied package name against the known set of
2092 // packages associated with this uid
2093 if (app.packageName.equals(packageName)) {
2094 // Add the caller to the set of pending backups. If there is
2095 // one already there, then overwrite it, but no harm done.
2096 BackupRequest req = new BackupRequest(app, false);
Christopher Tatec28083a2010-12-14 16:16:44 -08002097 if (mPendingBackups.put(app.packageName, req) == null) {
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002098 // Journal this request in case of crash. The put()
2099 // operation returned null when this package was not already
2100 // in the set; we want to avoid touching the disk redundantly.
2101 writeToJournalLocked(packageName);
2102
2103 if (DEBUG) {
2104 int numKeys = mPendingBackups.size();
2105 Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
2106 for (BackupRequest b : mPendingBackups.values()) {
2107 Slog.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
2108 }
2109 }
2110 }
2111 }
2112 }
2113 }
2114 }
2115
2116 // Note: packageName is currently unused, but may be in the future
2117 private HashSet<ApplicationInfo> dataChangedTargets(String packageName) {
Christopher Tate63d27002009-06-16 17:16:42 -07002118 // If the caller does not hold the BACKUP permission, it can only request a
2119 // backup of its own data.
Dianne Hackborncf098292009-07-01 19:55:20 -07002120 if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
Christopher Tate63d27002009-06-16 17:16:42 -07002121 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002122 synchronized (mBackupParticipants) {
2123 return mBackupParticipants.get(Binder.getCallingUid());
2124 }
2125 }
2126
2127 // a caller with full permission can ask to back up any participating app
2128 // !!! TODO: allow backup of ANY app?
2129 HashSet<ApplicationInfo> targets = new HashSet<ApplicationInfo>();
2130 synchronized (mBackupParticipants) {
Christopher Tate63d27002009-06-16 17:16:42 -07002131 int N = mBackupParticipants.size();
2132 for (int i = 0; i < N; i++) {
2133 HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
2134 if (s != null) {
2135 targets.addAll(s);
2136 }
2137 }
2138 }
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002139 return targets;
Christopher Tate487529a2009-04-29 14:03:25 -07002140 }
Christopher Tate46758122009-05-06 11:22:00 -07002141
Christopher Tatecde87f42009-06-12 12:55:53 -07002142 private void writeToJournalLocked(String str) {
Dan Egnor852f8e42009-09-30 11:20:45 -07002143 RandomAccessFile out = null;
2144 try {
2145 if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
2146 out = new RandomAccessFile(mJournal, "rws");
2147 out.seek(out.length());
2148 out.writeUTF(str);
2149 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002150 Slog.e(TAG, "Can't write " + str + " to backup journal", e);
Dan Egnor852f8e42009-09-30 11:20:45 -07002151 mJournal = null;
2152 } finally {
2153 try { if (out != null) out.close(); } catch (IOException e) {}
Christopher Tatecde87f42009-06-12 12:55:53 -07002154 }
2155 }
2156
Brad Fitzpatrick3dd42332010-09-07 23:40:30 -07002157 // ----- IBackupManager binder interface -----
2158
2159 public void dataChanged(final String packageName) {
2160 final HashSet<ApplicationInfo> targets = dataChangedTargets(packageName);
2161 if (targets == null) {
2162 Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
2163 + " uid=" + Binder.getCallingUid());
2164 return;
2165 }
2166
2167 mBackupHandler.post(new Runnable() {
2168 public void run() {
2169 dataChangedImpl(packageName, targets);
2170 }
2171 });
2172 }
2173
Christopher Tateee0e78a2009-07-02 11:17:03 -07002174 // Clear the given package's backup data from the current transport
2175 public void clearBackupData(String packageName) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002176 if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName);
Christopher Tateee0e78a2009-07-02 11:17:03 -07002177 PackageInfo info;
2178 try {
2179 info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
2180 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002181 Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
Christopher Tateee0e78a2009-07-02 11:17:03 -07002182 return;
2183 }
2184
2185 // If the caller does not hold the BACKUP permission, it can only request a
2186 // wipe of its own backed-up data.
2187 HashSet<ApplicationInfo> apps;
Christopher Tate4e3e50c2009-07-02 12:14:05 -07002188 if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
Christopher Tateee0e78a2009-07-02 11:17:03 -07002189 Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
2190 apps = mBackupParticipants.get(Binder.getCallingUid());
2191 } else {
2192 // a caller with full permission can ask to back up any participating app
2193 // !!! TODO: allow data-clear of ANY app?
Joe Onorato8a9b2202010-02-26 18:56:32 -08002194 if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
Christopher Tateee0e78a2009-07-02 11:17:03 -07002195 apps = new HashSet<ApplicationInfo>();
2196 int N = mBackupParticipants.size();
2197 for (int i = 0; i < N; i++) {
2198 HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
2199 if (s != null) {
2200 apps.addAll(s);
2201 }
2202 }
2203 }
2204
2205 // now find the given package in the set of candidate apps
2206 for (ApplicationInfo app : apps) {
2207 if (app.packageName.equals(packageName)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002208 if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
Christopher Tateee0e78a2009-07-02 11:17:03 -07002209 // found it; fire off the clear request
2210 synchronized (mQueueLock) {
Christopher Tateaa93b042009-08-05 18:21:40 -07002211 long oldId = Binder.clearCallingIdentity();
Christopher Tateb6787f22009-07-02 17:40:45 -07002212 mWakelock.acquire();
Christopher Tateee0e78a2009-07-02 11:17:03 -07002213 Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
2214 new ClearParams(getTransport(mCurrentTransport), info));
2215 mBackupHandler.sendMessage(msg);
Christopher Tateaa93b042009-08-05 18:21:40 -07002216 Binder.restoreCallingIdentity(oldId);
Christopher Tateee0e78a2009-07-02 11:17:03 -07002217 }
2218 break;
2219 }
2220 }
2221 }
2222
Christopher Tateace7f092009-06-15 18:07:25 -07002223 // Run a backup pass immediately for any applications that have declared
2224 // that they have pending updates.
Dan Egnor852f8e42009-09-30 11:20:45 -07002225 public void backupNow() {
Joe Onorato5933a492009-07-23 18:24:08 -04002226 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
Christopher Tate043dadc2009-06-02 16:11:00 -07002227
Joe Onorato8a9b2202010-02-26 18:56:32 -08002228 if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
Christopher Tate46758122009-05-06 11:22:00 -07002229 synchronized (mQueueLock) {
Christopher Tate21ab6a52009-09-24 18:01:46 -07002230 // Because the alarms we are using can jitter, and we want an *immediate*
2231 // backup pass to happen, we restart the timer beginning with "next time,"
2232 // then manually fire the backup trigger intent ourselves.
2233 startBackupAlarmsLocked(BACKUP_INTERVAL);
Christopher Tateb6787f22009-07-02 17:40:45 -07002234 try {
Christopher Tateb6787f22009-07-02 17:40:45 -07002235 mRunBackupIntent.send();
2236 } catch (PendingIntent.CanceledException e) {
2237 // should never happen
Joe Onorato8a9b2202010-02-26 18:56:32 -08002238 Slog.e(TAG, "run-backup intent cancelled!");
Christopher Tateb6787f22009-07-02 17:40:45 -07002239 }
Christopher Tate46758122009-05-06 11:22:00 -07002240 }
2241 }
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002242
Christopher Tate8031a3d2009-07-06 16:36:05 -07002243 // Enable/disable the backup service
Christopher Tate6ef58a12009-06-29 14:56:28 -07002244 public void setBackupEnabled(boolean enable) {
Christopher Tateb6787f22009-07-02 17:40:45 -07002245 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2246 "setBackupEnabled");
Christopher Tate6ef58a12009-06-29 14:56:28 -07002247
Joe Onorato8a9b2202010-02-26 18:56:32 -08002248 Slog.i(TAG, "Backup enabled => " + enable);
Christopher Tate4cc86e12009-09-21 19:36:51 -07002249
Christopher Tate6ef58a12009-06-29 14:56:28 -07002250 boolean wasEnabled = mEnabled;
2251 synchronized (this) {
Dianne Hackborncf098292009-07-01 19:55:20 -07002252 Settings.Secure.putInt(mContext.getContentResolver(),
2253 Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
Christopher Tate6ef58a12009-06-29 14:56:28 -07002254 mEnabled = enable;
2255 }
2256
Christopher Tate49401dd2009-07-01 12:34:29 -07002257 synchronized (mQueueLock) {
Christopher Tate8031a3d2009-07-06 16:36:05 -07002258 if (enable && !wasEnabled && mProvisioned) {
Christopher Tate49401dd2009-07-01 12:34:29 -07002259 // if we've just been enabled, start scheduling backup passes
Christopher Tate8031a3d2009-07-06 16:36:05 -07002260 startBackupAlarmsLocked(BACKUP_INTERVAL);
Christopher Tate49401dd2009-07-01 12:34:29 -07002261 } else if (!enable) {
Christopher Tateb6787f22009-07-02 17:40:45 -07002262 // No longer enabled, so stop running backups
Joe Onorato8a9b2202010-02-26 18:56:32 -08002263 if (DEBUG) Slog.i(TAG, "Opting out of backup");
Christopher Tate4cc86e12009-09-21 19:36:51 -07002264
Christopher Tateb6787f22009-07-02 17:40:45 -07002265 mAlarmManager.cancel(mRunBackupIntent);
Christopher Tate4cc86e12009-09-21 19:36:51 -07002266
2267 // This also constitutes an opt-out, so we wipe any data for
2268 // this device from the backend. We start that process with
2269 // an alarm in order to guarantee wakelock states.
2270 if (wasEnabled && mProvisioned) {
2271 // NOTE: we currently flush every registered transport, not just
2272 // the currently-active one.
2273 HashSet<String> allTransports;
2274 synchronized (mTransports) {
2275 allTransports = new HashSet<String>(mTransports.keySet());
2276 }
2277 // build the set of transports for which we are posting an init
2278 for (String transport : allTransports) {
2279 recordInitPendingLocked(true, transport);
2280 }
2281 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
2282 mRunInitIntent);
2283 }
Christopher Tate6ef58a12009-06-29 14:56:28 -07002284 }
2285 }
Christopher Tate49401dd2009-07-01 12:34:29 -07002286 }
Christopher Tate6ef58a12009-06-29 14:56:28 -07002287
Christopher Tatecce9da52010-02-03 15:11:15 -08002288 // Enable/disable automatic restore of app data at install time
2289 public void setAutoRestore(boolean doAutoRestore) {
2290 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2291 "setBackupEnabled");
2292
Joe Onorato8a9b2202010-02-26 18:56:32 -08002293 Slog.i(TAG, "Auto restore => " + doAutoRestore);
Christopher Tatecce9da52010-02-03 15:11:15 -08002294
2295 synchronized (this) {
2296 Settings.Secure.putInt(mContext.getContentResolver(),
2297 Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
2298 mAutoRestore = doAutoRestore;
2299 }
2300 }
2301
Christopher Tate8031a3d2009-07-06 16:36:05 -07002302 // Mark the backup service as having been provisioned
2303 public void setBackupProvisioned(boolean available) {
2304 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2305 "setBackupProvisioned");
2306
2307 boolean wasProvisioned = mProvisioned;
2308 synchronized (this) {
2309 Settings.Secure.putInt(mContext.getContentResolver(),
2310 Settings.Secure.BACKUP_PROVISIONED, available ? 1 : 0);
2311 mProvisioned = available;
2312 }
2313
2314 synchronized (mQueueLock) {
2315 if (available && !wasProvisioned && mEnabled) {
2316 // we're now good to go, so start the backup alarms
2317 startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
2318 } else if (!available) {
2319 // No longer enabled, so stop running backups
Joe Onorato8a9b2202010-02-26 18:56:32 -08002320 Slog.w(TAG, "Backup service no longer provisioned");
Christopher Tate8031a3d2009-07-06 16:36:05 -07002321 mAlarmManager.cancel(mRunBackupIntent);
2322 }
2323 }
2324 }
2325
2326 private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
Dan Egnorc1c49c02009-10-30 17:35:39 -07002327 // We used to use setInexactRepeating(), but that may be linked to
2328 // backups running at :00 more often than not, creating load spikes.
2329 // Schedule at an exact time for now, and also add a bit of "fuzz".
2330
2331 Random random = new Random();
2332 long when = System.currentTimeMillis() + delayBeforeFirstBackup +
2333 random.nextInt(FUZZ_MILLIS);
2334 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
2335 BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
Christopher Tate55f931a2009-09-29 17:17:34 -07002336 mNextBackupPass = when;
Christopher Tate8031a3d2009-07-06 16:36:05 -07002337 }
2338
Christopher Tate6ef58a12009-06-29 14:56:28 -07002339 // Report whether the backup mechanism is currently enabled
2340 public boolean isBackupEnabled() {
Joe Onorato5933a492009-07-23 18:24:08 -04002341 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
Christopher Tate6ef58a12009-06-29 14:56:28 -07002342 return mEnabled; // no need to synchronize just to read it
2343 }
2344
Christopher Tate91717492009-06-26 21:07:13 -07002345 // Report the name of the currently active transport
2346 public String getCurrentTransport() {
Joe Onorato5933a492009-07-23 18:24:08 -04002347 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
Christopher Tate4e3e50c2009-07-02 12:14:05 -07002348 "getCurrentTransport");
Joe Onorato8a9b2202010-02-26 18:56:32 -08002349 if (DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
Christopher Tate91717492009-06-26 21:07:13 -07002350 return mCurrentTransport;
Christopher Tateace7f092009-06-15 18:07:25 -07002351 }
2352
Christopher Tate91717492009-06-26 21:07:13 -07002353 // Report all known, available backup transports
2354 public String[] listAllTransports() {
Christopher Tate34ebd0e2009-07-06 15:44:54 -07002355 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
Christopher Tate043dadc2009-06-02 16:11:00 -07002356
Christopher Tate91717492009-06-26 21:07:13 -07002357 String[] list = null;
2358 ArrayList<String> known = new ArrayList<String>();
2359 for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
2360 if (entry.getValue() != null) {
2361 known.add(entry.getKey());
2362 }
2363 }
2364
2365 if (known.size() > 0) {
2366 list = new String[known.size()];
2367 known.toArray(list);
2368 }
2369 return list;
2370 }
2371
2372 // Select which transport to use for the next backup operation. If the given
2373 // name is not one of the available transports, no action is taken and the method
2374 // returns null.
2375 public String selectBackupTransport(String transport) {
Joe Onorato5933a492009-07-23 18:24:08 -04002376 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
Christopher Tate91717492009-06-26 21:07:13 -07002377
2378 synchronized (mTransports) {
2379 String prevTransport = null;
2380 if (mTransports.get(transport) != null) {
2381 prevTransport = mCurrentTransport;
2382 mCurrentTransport = transport;
Dianne Hackborncf098292009-07-01 19:55:20 -07002383 Settings.Secure.putString(mContext.getContentResolver(),
2384 Settings.Secure.BACKUP_TRANSPORT, transport);
Joe Onorato8a9b2202010-02-26 18:56:32 -08002385 Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
Christopher Tate91717492009-06-26 21:07:13 -07002386 + " returning " + prevTransport);
2387 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002388 Slog.w(TAG, "Attempt to select unavailable transport " + transport);
Christopher Tate91717492009-06-26 21:07:13 -07002389 }
2390 return prevTransport;
2391 }
Christopher Tate043dadc2009-06-02 16:11:00 -07002392 }
2393
Christopher Tatef5e1c292010-12-08 18:40:26 -08002394 // Supply the configuration Intent for the given transport. If the name is not one
2395 // of the available transports, or if the transport does not supply any configuration
2396 // UI, the method returns null.
2397 public Intent getConfigurationIntent(String transportName) {
2398 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2399 "getConfigurationIntent");
2400
2401 synchronized (mTransports) {
2402 final IBackupTransport transport = mTransports.get(transportName);
2403 if (transport != null) {
2404 try {
2405 final Intent intent = transport.configurationIntent();
2406 if (DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
2407 + intent);
2408 return intent;
2409 } catch (RemoteException e) {
2410 /* fall through to return null */
2411 }
2412 }
2413 }
2414
2415 return null;
2416 }
2417
2418 // Supply the configuration summary string for the given transport. If the name is
2419 // not one of the available transports, or if the transport does not supply any
2420 // summary / destination string, the method can return null.
2421 //
2422 // This string is used VERBATIM as the summary text of the relevant Settings item!
2423 public String getDestinationString(String transportName) {
2424 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2425 "getConfigurationIntent");
2426
2427 synchronized (mTransports) {
2428 final IBackupTransport transport = mTransports.get(transportName);
2429 if (transport != null) {
2430 try {
2431 final String text = transport.currentDestinationString();
2432 if (DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
2433 return text;
2434 } catch (RemoteException e) {
2435 /* fall through to return null */
2436 }
2437 }
2438 }
2439
2440 return null;
2441 }
2442
Christopher Tate043dadc2009-06-02 16:11:00 -07002443 // Callback: a requested backup agent has been instantiated. This should only
2444 // be called from the Activity Manager.
Christopher Tate181fafa2009-05-14 11:12:14 -07002445 public void agentConnected(String packageName, IBinder agentBinder) {
Christopher Tate043dadc2009-06-02 16:11:00 -07002446 synchronized(mAgentConnectLock) {
2447 if (Binder.getCallingUid() == Process.SYSTEM_UID) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002448 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
Christopher Tate043dadc2009-06-02 16:11:00 -07002449 IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
2450 mConnectedAgent = agent;
2451 mConnecting = false;
2452 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002453 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
Christopher Tate043dadc2009-06-02 16:11:00 -07002454 + " claiming agent connected");
2455 }
2456 mAgentConnectLock.notifyAll();
2457 }
Christopher Tate181fafa2009-05-14 11:12:14 -07002458 }
2459
2460 // Callback: a backup agent has failed to come up, or has unexpectedly quit.
2461 // If the agent failed to come up in the first place, the agentBinder argument
Christopher Tate043dadc2009-06-02 16:11:00 -07002462 // will be null. This should only be called from the Activity Manager.
Christopher Tate181fafa2009-05-14 11:12:14 -07002463 public void agentDisconnected(String packageName) {
2464 // TODO: handle backup being interrupted
Christopher Tate043dadc2009-06-02 16:11:00 -07002465 synchronized(mAgentConnectLock) {
2466 if (Binder.getCallingUid() == Process.SYSTEM_UID) {
2467 mConnectedAgent = null;
2468 mConnecting = false;
2469 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002470 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
Christopher Tate043dadc2009-06-02 16:11:00 -07002471 + " claiming agent disconnected");
2472 }
2473 mAgentConnectLock.notifyAll();
2474 }
Christopher Tate181fafa2009-05-14 11:12:14 -07002475 }
Christopher Tate181fafa2009-05-14 11:12:14 -07002476
Christopher Tate1bb69062010-02-19 17:02:12 -08002477 // An application being installed will need a restore pass, then the Package Manager
2478 // will need to be told when the restore is finished.
2479 public void restoreAtInstall(String packageName, int token) {
2480 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002481 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
Christopher Tate1bb69062010-02-19 17:02:12 -08002482 + " attemping install-time restore");
2483 return;
2484 }
2485
2486 long restoreSet = getAvailableRestoreToken(packageName);
Joe Onorato8a9b2202010-02-26 18:56:32 -08002487 if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
Christopher Tate1bb69062010-02-19 17:02:12 -08002488 + " token=" + Integer.toHexString(token));
2489
Christopher Tatef0872722010-02-25 15:22:48 -08002490 if (mAutoRestore && mProvisioned && restoreSet != 0) {
Christopher Tate1bb69062010-02-19 17:02:12 -08002491 // okay, we're going to attempt a restore of this package from this restore set.
2492 // The eventual message back into the Package Manager to run the post-install
2493 // steps for 'token' will be issued from the restore handling code.
2494
2495 // We can use a synthetic PackageInfo here because:
2496 // 1. We know it's valid, since the Package Manager supplied the name
2497 // 2. Only the packageName field will be used by the restore code
2498 PackageInfo pkg = new PackageInfo();
2499 pkg.packageName = packageName;
2500
2501 mWakelock.acquire();
2502 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
2503 msg.obj = new RestoreParams(getTransport(mCurrentTransport), null,
Chris Tate249345b2010-10-29 12:57:04 -07002504 restoreSet, pkg, token, true);
Christopher Tate1bb69062010-02-19 17:02:12 -08002505 mBackupHandler.sendMessage(msg);
2506 } else {
Christopher Tatef0872722010-02-25 15:22:48 -08002507 // Auto-restore disabled or no way to attempt a restore; just tell the Package
2508 // Manager to proceed with the post-install handling for this package.
Joe Onorato8a9b2202010-02-26 18:56:32 -08002509 if (DEBUG) Slog.v(TAG, "No restore set -- skipping restore");
Christopher Tate1bb69062010-02-19 17:02:12 -08002510 try {
2511 mPackageManagerBinder.finishPackageInstall(token);
2512 } catch (RemoteException e) { /* can't happen */ }
2513 }
2514 }
2515
Christopher Tate8c850b72009-06-07 19:33:20 -07002516 // Hand off a restore session
Chris Tate44ab8452010-11-16 15:10:49 -08002517 public IRestoreSession beginRestoreSession(String packageName, String transport) {
2518 if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
2519 + " transport=" + transport);
2520
2521 boolean needPermission = true;
2522 if (transport == null) {
2523 transport = mCurrentTransport;
2524
2525 if (packageName != null) {
2526 PackageInfo app = null;
2527 try {
2528 app = mPackageManager.getPackageInfo(packageName, 0);
2529 } catch (NameNotFoundException nnf) {
2530 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
2531 throw new IllegalArgumentException("Package " + packageName + " not found");
2532 }
2533
2534 if (app.applicationInfo.uid == Binder.getCallingUid()) {
2535 // So: using the current active transport, and the caller has asked
2536 // that its own package will be restored. In this narrow use case
2537 // we do not require the caller to hold the permission.
2538 needPermission = false;
2539 }
2540 }
2541 }
2542
2543 if (needPermission) {
2544 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2545 "beginRestoreSession");
2546 } else {
2547 if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
2548 }
Christopher Tatef68eb502009-06-16 11:02:01 -07002549
2550 synchronized(this) {
2551 if (mActiveRestoreSession != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002552 Slog.d(TAG, "Restore session requested but one already active");
Christopher Tatef68eb502009-06-16 11:02:01 -07002553 return null;
2554 }
Chris Tate44ab8452010-11-16 15:10:49 -08002555 mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
Christopher Tate73a3cb32010-12-13 18:27:26 -08002556 mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
Christopher Tatef68eb502009-06-16 11:02:01 -07002557 }
2558 return mActiveRestoreSession;
Christopher Tate8c850b72009-06-07 19:33:20 -07002559 }
Christopher Tate043dadc2009-06-02 16:11:00 -07002560
Christopher Tate73a3cb32010-12-13 18:27:26 -08002561 void clearRestoreSession(ActiveRestoreSession currentSession) {
2562 synchronized(this) {
2563 if (currentSession != mActiveRestoreSession) {
2564 Slog.e(TAG, "ending non-current restore session");
2565 } else {
2566 if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
2567 mActiveRestoreSession = null;
2568 mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
2569 }
2570 }
2571 }
2572
Christopher Tate44a27902010-01-27 17:15:49 -08002573 // Note that a currently-active backup agent has notified us that it has
2574 // completed the given outstanding asynchronous backup/restore operation.
2575 public void opComplete(int token) {
2576 synchronized (mCurrentOpLock) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002577 if (DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
Christopher Tate44a27902010-01-27 17:15:49 -08002578 mCurrentOperations.put(token, OP_ACKNOWLEDGED);
2579 mCurrentOpLock.notifyAll();
2580 }
2581 }
2582
Christopher Tate9b3905c2009-06-08 15:24:01 -07002583 // ----- Restore session -----
2584
Christopher Tate80202c82010-01-25 19:37:47 -08002585 class ActiveRestoreSession extends IRestoreSession.Stub {
Christopher Tatef68eb502009-06-16 11:02:01 -07002586 private static final String TAG = "RestoreSession";
2587
Chris Tate44ab8452010-11-16 15:10:49 -08002588 private String mPackageName;
Christopher Tate9b3905c2009-06-08 15:24:01 -07002589 private IBackupTransport mRestoreTransport = null;
2590 RestoreSet[] mRestoreSets = null;
Christopher Tate73a3cb32010-12-13 18:27:26 -08002591 boolean mEnded = false;
Christopher Tate9b3905c2009-06-08 15:24:01 -07002592
Chris Tate44ab8452010-11-16 15:10:49 -08002593 ActiveRestoreSession(String packageName, String transport) {
2594 mPackageName = packageName;
Christopher Tate91717492009-06-26 21:07:13 -07002595 mRestoreTransport = getTransport(transport);
Christopher Tate9b3905c2009-06-08 15:24:01 -07002596 }
2597
2598 // --- Binder interface ---
Christopher Tate2d449afe2010-03-29 19:14:24 -07002599 public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
Joe Onorato5933a492009-07-23 18:24:08 -04002600 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
Christopher Tate9bbc21a2009-06-10 20:23:25 -07002601 "getAvailableRestoreSets");
Christopher Tate2d449afe2010-03-29 19:14:24 -07002602 if (observer == null) {
2603 throw new IllegalArgumentException("Observer must not be null");
2604 }
Christopher Tate9bbc21a2009-06-10 20:23:25 -07002605
Christopher Tate73a3cb32010-12-13 18:27:26 -08002606 if (mEnded) {
2607 throw new IllegalStateException("Restore session already ended");
2608 }
2609
Christopher Tate1bb69062010-02-19 17:02:12 -08002610 long oldId = Binder.clearCallingIdentity();
Christopher Tatef68eb502009-06-16 11:02:01 -07002611 try {
Christopher Tate43383042009-07-13 15:17:13 -07002612 if (mRestoreTransport == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002613 Slog.w(TAG, "Null transport getting restore sets");
Christopher Tate2d449afe2010-03-29 19:14:24 -07002614 return -1;
Dan Egnor0084da52009-07-29 12:57:16 -07002615 }
Christopher Tate2d449afe2010-03-29 19:14:24 -07002616 // spin off the transport request to our service thread
2617 mWakelock.acquire();
2618 Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
2619 new RestoreGetSetsParams(mRestoreTransport, this, observer));
2620 mBackupHandler.sendMessage(msg);
2621 return 0;
Dan Egnor0084da52009-07-29 12:57:16 -07002622 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002623 Slog.e(TAG, "Error in getAvailableRestoreSets", e);
Christopher Tate2d449afe2010-03-29 19:14:24 -07002624 return -1;
Christopher Tate1bb69062010-02-19 17:02:12 -08002625 } finally {
2626 Binder.restoreCallingIdentity(oldId);
Christopher Tatef68eb502009-06-16 11:02:01 -07002627 }
Christopher Tate9b3905c2009-06-08 15:24:01 -07002628 }
2629
Christopher Tate84725812010-02-04 15:52:40 -08002630 public synchronized int restoreAll(long token, IRestoreObserver observer) {
Dan Egnor0084da52009-07-29 12:57:16 -07002631 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
2632 "performRestore");
Christopher Tate9bbc21a2009-06-10 20:23:25 -07002633
Chris Tate44ab8452010-11-16 15:10:49 -08002634 if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
Christopher Tatef2c321a2009-08-10 15:43:36 -07002635 + " observer=" + observer);
Joe Onorato9a5e3e12009-07-01 21:04:03 -04002636
Christopher Tate73a3cb32010-12-13 18:27:26 -08002637 if (mEnded) {
2638 throw new IllegalStateException("Restore session already ended");
2639 }
2640
Dan Egnor0084da52009-07-29 12:57:16 -07002641 if (mRestoreTransport == null || mRestoreSets == null) {
Chris Tate44ab8452010-11-16 15:10:49 -08002642 Slog.e(TAG, "Ignoring restoreAll() with no restore set");
2643 return -1;
2644 }
2645
2646 if (mPackageName != null) {
2647 Slog.e(TAG, "Ignoring restoreAll() on single-package session");
Dan Egnor0084da52009-07-29 12:57:16 -07002648 return -1;
2649 }
2650
Christopher Tate21ab6a52009-09-24 18:01:46 -07002651 synchronized (mQueueLock) {
Christopher Tate21ab6a52009-09-24 18:01:46 -07002652 for (int i = 0; i < mRestoreSets.length; i++) {
2653 if (token == mRestoreSets[i].token) {
2654 long oldId = Binder.clearCallingIdentity();
Christopher Tate21ab6a52009-09-24 18:01:46 -07002655 mWakelock.acquire();
2656 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
Chris Tate249345b2010-10-29 12:57:04 -07002657 msg.obj = new RestoreParams(mRestoreTransport, observer, token, true);
Christopher Tate21ab6a52009-09-24 18:01:46 -07002658 mBackupHandler.sendMessage(msg);
2659 Binder.restoreCallingIdentity(oldId);
2660 return 0;
2661 }
Christopher Tate9bbc21a2009-06-10 20:23:25 -07002662 }
2663 }
Christopher Tate0e0b4ae2009-08-10 16:13:47 -07002664
Joe Onorato8a9b2202010-02-26 18:56:32 -08002665 Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
Christopher Tate9b3905c2009-06-08 15:24:01 -07002666 return -1;
2667 }
2668
Christopher Tate84725812010-02-04 15:52:40 -08002669 public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002670 if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
Christopher Tate84725812010-02-04 15:52:40 -08002671
Christopher Tate73a3cb32010-12-13 18:27:26 -08002672 if (mEnded) {
2673 throw new IllegalStateException("Restore session already ended");
2674 }
2675
Chris Tate44ab8452010-11-16 15:10:49 -08002676 if (mPackageName != null) {
2677 if (! mPackageName.equals(packageName)) {
2678 Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
2679 + " on session for package " + mPackageName);
2680 return -1;
2681 }
2682 }
2683
Christopher Tate84725812010-02-04 15:52:40 -08002684 PackageInfo app = null;
2685 try {
2686 app = mPackageManager.getPackageInfo(packageName, 0);
2687 } catch (NameNotFoundException nnf) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002688 Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
Christopher Tate84725812010-02-04 15:52:40 -08002689 return -1;
2690 }
2691
2692 // If the caller is not privileged and is not coming from the target
2693 // app's uid, throw a permission exception back to the caller.
2694 int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
2695 Binder.getCallingPid(), Binder.getCallingUid());
2696 if ((perm == PackageManager.PERMISSION_DENIED) &&
2697 (app.applicationInfo.uid != Binder.getCallingUid())) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002698 Slog.w(TAG, "restorePackage: bad packageName=" + packageName
Christopher Tate84725812010-02-04 15:52:40 -08002699 + " or calling uid=" + Binder.getCallingUid());
2700 throw new SecurityException("No permission to restore other packages");
2701 }
2702
Christopher Tate7d411a32010-02-26 11:27:08 -08002703 // If the package has no backup agent, we obviously cannot proceed
2704 if (app.applicationInfo.backupAgentName == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002705 Slog.w(TAG, "Asked to restore package " + packageName + " with no agent");
Christopher Tate7d411a32010-02-26 11:27:08 -08002706 return -1;
2707 }
2708
Christopher Tate84725812010-02-04 15:52:40 -08002709 // So far so good; we're allowed to try to restore this package. Now
2710 // check whether there is data for it in the current dataset, falling back
2711 // to the ancestral dataset if not.
Christopher Tate1bb69062010-02-19 17:02:12 -08002712 long token = getAvailableRestoreToken(packageName);
Christopher Tate84725812010-02-04 15:52:40 -08002713
2714 // If we didn't come up with a place to look -- no ancestral dataset and
2715 // the app has never been backed up from this device -- there's nothing
2716 // to do but return failure.
2717 if (token == 0) {
Chris Tate44ab8452010-11-16 15:10:49 -08002718 if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
Christopher Tate84725812010-02-04 15:52:40 -08002719 return -1;
2720 }
2721
2722 // Ready to go: enqueue the restore request and claim success
2723 long oldId = Binder.clearCallingIdentity();
2724 mWakelock.acquire();
2725 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
Chris Tate249345b2010-10-29 12:57:04 -07002726 msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0, false);
Christopher Tate84725812010-02-04 15:52:40 -08002727 mBackupHandler.sendMessage(msg);
2728 Binder.restoreCallingIdentity(oldId);
2729 return 0;
2730 }
2731
Christopher Tate73a3cb32010-12-13 18:27:26 -08002732 // Posted to the handler to tear down a restore session in a cleanly synchronized way
2733 class EndRestoreRunnable implements Runnable {
2734 BackupManagerService mBackupManager;
2735 ActiveRestoreSession mSession;
2736
2737 EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
2738 mBackupManager = manager;
2739 mSession = session;
2740 }
2741
2742 public void run() {
2743 // clean up the session's bookkeeping
2744 synchronized (mSession) {
2745 try {
2746 if (mSession.mRestoreTransport != null) {
2747 mSession.mRestoreTransport.finishRestore();
2748 }
2749 } catch (Exception e) {
2750 Slog.e(TAG, "Error in finishRestore", e);
2751 } finally {
2752 mSession.mRestoreTransport = null;
2753 mSession.mEnded = true;
2754 }
2755 }
2756
2757 // clean up the BackupManagerService side of the bookkeeping
2758 // and cancel any pending timeout message
2759 mBackupManager.clearRestoreSession(mSession);
2760 }
2761 }
2762
Dan Egnor0084da52009-07-29 12:57:16 -07002763 public synchronized void endRestoreSession() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002764 if (DEBUG) Slog.d(TAG, "endRestoreSession");
Joe Onorato9a5e3e12009-07-01 21:04:03 -04002765
Christopher Tate73a3cb32010-12-13 18:27:26 -08002766 if (mEnded) {
2767 throw new IllegalStateException("Restore session already ended");
Dan Egnor0084da52009-07-29 12:57:16 -07002768 }
2769
Christopher Tate73a3cb32010-12-13 18:27:26 -08002770 mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
Christopher Tate9b3905c2009-06-08 15:24:01 -07002771 }
2772 }
2773
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002774 @Override
2775 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2776 synchronized (mQueueLock) {
Christopher Tate8031a3d2009-07-06 16:36:05 -07002777 pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
Christopher Tate55f931a2009-09-29 17:17:34 -07002778 + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
Christopher Tatec2af5d32010-02-02 15:18:58 -08002779 + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
Christopher Tateae06ed92010-02-25 17:13:28 -08002780 pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
Christopher Tate55f931a2009-09-29 17:17:34 -07002781 pw.println("Last backup pass: " + mLastBackupPass
2782 + " (now = " + System.currentTimeMillis() + ')');
2783 pw.println(" next scheduled: " + mNextBackupPass);
2784
Christopher Tate91717492009-06-26 21:07:13 -07002785 pw.println("Available transports:");
2786 for (String t : listAllTransports()) {
Dan Egnor852f8e42009-09-30 11:20:45 -07002787 pw.println((t.equals(mCurrentTransport) ? " * " : " ") + t);
2788 try {
2789 File dir = new File(mBaseStateDir, getTransport(t).transportDirName());
2790 for (File f : dir.listFiles()) {
2791 pw.println(" " + f.getName() + " - " + f.length() + " state bytes");
2792 }
2793 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002794 Slog.e(TAG, "Error in transportDirName()", e);
Dan Egnor852f8e42009-09-30 11:20:45 -07002795 pw.println(" Error: " + e);
2796 }
Christopher Tate91717492009-06-26 21:07:13 -07002797 }
Christopher Tate55f931a2009-09-29 17:17:34 -07002798
2799 pw.println("Pending init: " + mPendingInits.size());
2800 for (String s : mPendingInits) {
2801 pw.println(" " + s);
2802 }
2803
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002804 int N = mBackupParticipants.size();
Christopher Tate55f931a2009-09-29 17:17:34 -07002805 pw.println("Participants:");
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002806 for (int i=0; i<N; i++) {
2807 int uid = mBackupParticipants.keyAt(i);
2808 pw.print(" uid: ");
2809 pw.println(uid);
Christopher Tate181fafa2009-05-14 11:12:14 -07002810 HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
2811 for (ApplicationInfo app: participants) {
Christopher Tate55f931a2009-09-29 17:17:34 -07002812 pw.println(" " + app.packageName);
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002813 }
2814 }
Christopher Tate55f931a2009-09-29 17:17:34 -07002815
Christopher Tateb49ceb32010-02-08 16:22:24 -08002816 pw.println("Ancestral packages: "
2817 + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
Christopher Tate5923c972010-04-04 17:45:35 -07002818 if (mAncestralPackages != null) {
2819 for (String pkg : mAncestralPackages) {
2820 pw.println(" " + pkg);
2821 }
Christopher Tateb49ceb32010-02-08 16:22:24 -08002822 }
2823
Christopher Tate73e02522009-07-15 14:18:26 -07002824 pw.println("Ever backed up: " + mEverStoredApps.size());
2825 for (String pkg : mEverStoredApps) {
2826 pw.println(" " + pkg);
2827 }
Christopher Tate55f931a2009-09-29 17:17:34 -07002828
2829 pw.println("Pending backup: " + mPendingBackups.size());
Christopher Tate6aa41f42009-06-19 14:14:22 -07002830 for (BackupRequest req : mPendingBackups.values()) {
Christopher Tate6ef58a12009-06-29 14:56:28 -07002831 pw.println(" " + req);
Christopher Tate181fafa2009-05-14 11:12:14 -07002832 }
Joe Onoratob1a7ffe2009-05-06 18:06:21 -07002833 }
2834 }
Christopher Tate487529a2009-04-29 14:03:25 -07002835}