PageRenderTime 182ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 3ms

/services/java/com/android/server/BackupManagerService.java

https://github.com/aizuzi/platform_frameworks_base
Java | 6288 lines | 4725 code | 698 blank | 865 comment | 1000 complexity | 7a00f18c337f24c4bb4331b40a664d70 MD5 | raw file
  1. /*
  2. * Copyright (C) 2009 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.server;
  17. import android.app.ActivityManagerNative;
  18. import android.app.AlarmManager;
  19. import android.app.AppGlobals;
  20. import android.app.IActivityManager;
  21. import android.app.IApplicationThread;
  22. import android.app.IBackupAgent;
  23. import android.app.PendingIntent;
  24. import android.app.backup.BackupAgent;
  25. import android.app.backup.BackupDataOutput;
  26. import android.app.backup.FullBackup;
  27. import android.app.backup.RestoreSet;
  28. import android.app.backup.IBackupManager;
  29. import android.app.backup.IFullBackupRestoreObserver;
  30. import android.app.backup.IRestoreObserver;
  31. import android.app.backup.IRestoreSession;
  32. import android.content.ActivityNotFoundException;
  33. import android.content.BroadcastReceiver;
  34. import android.content.ComponentName;
  35. import android.content.ContentResolver;
  36. import android.content.Context;
  37. import android.content.Intent;
  38. import android.content.IntentFilter;
  39. import android.content.ServiceConnection;
  40. import android.content.pm.ApplicationInfo;
  41. import android.content.pm.IPackageDataObserver;
  42. import android.content.pm.IPackageDeleteObserver;
  43. import android.content.pm.IPackageInstallObserver;
  44. import android.content.pm.IPackageManager;
  45. import android.content.pm.PackageInfo;
  46. import android.content.pm.PackageManager;
  47. import android.content.pm.ResolveInfo;
  48. import android.content.pm.ServiceInfo;
  49. import android.content.pm.Signature;
  50. import android.content.pm.PackageManager.NameNotFoundException;
  51. import android.database.ContentObserver;
  52. import android.net.Uri;
  53. import android.os.Binder;
  54. import android.os.Build;
  55. import android.os.Bundle;
  56. import android.os.Environment;
  57. import android.os.Handler;
  58. import android.os.HandlerThread;
  59. import android.os.IBinder;
  60. import android.os.Looper;
  61. import android.os.Message;
  62. import android.os.ParcelFileDescriptor;
  63. import android.os.PowerManager;
  64. import android.os.Process;
  65. import android.os.RemoteException;
  66. import android.os.SELinux;
  67. import android.os.ServiceManager;
  68. import android.os.SystemClock;
  69. import android.os.UserHandle;
  70. import android.os.WorkSource;
  71. import android.os.Environment.UserEnvironment;
  72. import android.os.storage.IMountService;
  73. import android.provider.Settings;
  74. import android.util.EventLog;
  75. import android.util.Log;
  76. import android.util.Slog;
  77. import android.util.SparseArray;
  78. import android.util.StringBuilderPrinter;
  79. import com.android.internal.backup.BackupConstants;
  80. import com.android.internal.backup.IBackupTransport;
  81. import com.android.internal.backup.IObbBackupService;
  82. import com.android.server.EventLogTags;
  83. import com.android.server.PackageManagerBackupAgent.Metadata;
  84. import java.io.BufferedInputStream;
  85. import java.io.BufferedOutputStream;
  86. import java.io.ByteArrayOutputStream;
  87. import java.io.DataInputStream;
  88. import java.io.DataOutputStream;
  89. import java.io.EOFException;
  90. import java.io.File;
  91. import java.io.FileDescriptor;
  92. import java.io.FileInputStream;
  93. import java.io.FileNotFoundException;
  94. import java.io.FileOutputStream;
  95. import java.io.IOException;
  96. import java.io.InputStream;
  97. import java.io.OutputStream;
  98. import java.io.PrintWriter;
  99. import java.io.RandomAccessFile;
  100. import java.security.InvalidAlgorithmParameterException;
  101. import java.security.InvalidKeyException;
  102. import java.security.Key;
  103. import java.security.NoSuchAlgorithmException;
  104. import java.security.SecureRandom;
  105. import java.security.spec.InvalidKeySpecException;
  106. import java.security.spec.KeySpec;
  107. import java.text.SimpleDateFormat;
  108. import java.util.ArrayList;
  109. import java.util.Arrays;
  110. import java.util.Date;
  111. import java.util.HashMap;
  112. import java.util.HashSet;
  113. import java.util.List;
  114. import java.util.Map;
  115. import java.util.Random;
  116. import java.util.Set;
  117. import java.util.concurrent.atomic.AtomicBoolean;
  118. import java.util.zip.Deflater;
  119. import java.util.zip.DeflaterOutputStream;
  120. import java.util.zip.InflaterInputStream;
  121. import javax.crypto.BadPaddingException;
  122. import javax.crypto.Cipher;
  123. import javax.crypto.CipherInputStream;
  124. import javax.crypto.CipherOutputStream;
  125. import javax.crypto.IllegalBlockSizeException;
  126. import javax.crypto.NoSuchPaddingException;
  127. import javax.crypto.SecretKey;
  128. import javax.crypto.SecretKeyFactory;
  129. import javax.crypto.spec.IvParameterSpec;
  130. import javax.crypto.spec.PBEKeySpec;
  131. import javax.crypto.spec.SecretKeySpec;
  132. class BackupManagerService extends IBackupManager.Stub {
  133. private static final String TAG = "BackupManagerService";
  134. private static final boolean DEBUG = true;
  135. private static final boolean MORE_DEBUG = false;
  136. // Historical and current algorithm names
  137. static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
  138. static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
  139. // Name and current contents version of the full-backup manifest file
  140. static final String BACKUP_MANIFEST_FILENAME = "_manifest";
  141. static final int BACKUP_MANIFEST_VERSION = 1;
  142. static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
  143. static final int BACKUP_FILE_VERSION = 2;
  144. static final int BACKUP_PW_FILE_VERSION = 2;
  145. static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
  146. static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
  147. static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
  148. // How often we perform a backup pass. Privileged external callers can
  149. // trigger an immediate pass.
  150. private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
  151. // Random variation in backup scheduling time to avoid server load spikes
  152. private static final int FUZZ_MILLIS = 5 * 60 * 1000;
  153. // The amount of time between the initial provisioning of the device and
  154. // the first backup pass.
  155. private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
  156. // Retry interval for clear/init when the transport is unavailable
  157. private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
  158. private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
  159. private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
  160. private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
  161. private static final int MSG_RUN_BACKUP = 1;
  162. private static final int MSG_RUN_FULL_BACKUP = 2;
  163. private static final int MSG_RUN_RESTORE = 3;
  164. private static final int MSG_RUN_CLEAR = 4;
  165. private static final int MSG_RUN_INITIALIZE = 5;
  166. private static final int MSG_RUN_GET_RESTORE_SETS = 6;
  167. private static final int MSG_TIMEOUT = 7;
  168. private static final int MSG_RESTORE_TIMEOUT = 8;
  169. private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
  170. private static final int MSG_RUN_FULL_RESTORE = 10;
  171. private static final int MSG_RETRY_INIT = 11;
  172. private static final int MSG_RETRY_CLEAR = 12;
  173. // backup task state machine tick
  174. static final int MSG_BACKUP_RESTORE_STEP = 20;
  175. static final int MSG_OP_COMPLETE = 21;
  176. // Timeout interval for deciding that a bind or clear-data has taken too long
  177. static final long TIMEOUT_INTERVAL = 10 * 1000;
  178. // Timeout intervals for agent backup & restore operations
  179. static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
  180. static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
  181. static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
  182. static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
  183. // User confirmation timeout for a full backup/restore operation. It's this long in
  184. // order to give them time to enter the backup password.
  185. static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
  186. private Context mContext;
  187. private PackageManager mPackageManager;
  188. IPackageManager mPackageManagerBinder;
  189. private IActivityManager mActivityManager;
  190. private PowerManager mPowerManager;
  191. private AlarmManager mAlarmManager;
  192. private IMountService mMountService;
  193. IBackupManager mBackupManagerBinder;
  194. boolean mEnabled; // access to this is synchronized on 'this'
  195. boolean mProvisioned;
  196. boolean mAutoRestore;
  197. PowerManager.WakeLock mWakelock;
  198. HandlerThread mHandlerThread;
  199. BackupHandler mBackupHandler;
  200. PendingIntent mRunBackupIntent, mRunInitIntent;
  201. BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
  202. // map UIDs to the set of participating packages under that UID
  203. final SparseArray<HashSet<String>> mBackupParticipants
  204. = new SparseArray<HashSet<String>>();
  205. // set of backup services that have pending changes
  206. class BackupRequest {
  207. public String packageName;
  208. BackupRequest(String pkgName) {
  209. packageName = pkgName;
  210. }
  211. public String toString() {
  212. return "BackupRequest{pkg=" + packageName + "}";
  213. }
  214. }
  215. // Backups that we haven't started yet. Keys are package names.
  216. HashMap<String,BackupRequest> mPendingBackups
  217. = new HashMap<String,BackupRequest>();
  218. // Pseudoname that we use for the Package Manager metadata "package"
  219. static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
  220. // locking around the pending-backup management
  221. final Object mQueueLock = new Object();
  222. // The thread performing the sequence of queued backups binds to each app's agent
  223. // in succession. Bind notifications are asynchronously delivered through the
  224. // Activity Manager; use this lock object to signal when a requested binding has
  225. // completed.
  226. final Object mAgentConnectLock = new Object();
  227. IBackupAgent mConnectedAgent;
  228. volatile boolean mBackupRunning;
  229. volatile boolean mConnecting;
  230. volatile long mLastBackupPass;
  231. volatile long mNextBackupPass;
  232. // For debugging, we maintain a progress trace of operations during backup
  233. static final boolean DEBUG_BACKUP_TRACE = true;
  234. final List<String> mBackupTrace = new ArrayList<String>();
  235. // A similar synchronization mechanism around clearing apps' data for restore
  236. final Object mClearDataLock = new Object();
  237. volatile boolean mClearingData;
  238. // Transport bookkeeping
  239. final HashMap<String,String> mTransportNames
  240. = new HashMap<String,String>(); // component name -> registration name
  241. final HashMap<String,IBackupTransport> mTransports
  242. = new HashMap<String,IBackupTransport>(); // registration name -> binder
  243. final ArrayList<TransportConnection> mTransportConnections
  244. = new ArrayList<TransportConnection>();
  245. String mCurrentTransport;
  246. ActiveRestoreSession mActiveRestoreSession;
  247. // Watch the device provisioning operation during setup
  248. ContentObserver mProvisionedObserver;
  249. class ProvisionedObserver extends ContentObserver {
  250. public ProvisionedObserver(Handler handler) {
  251. super(handler);
  252. }
  253. public void onChange(boolean selfChange) {
  254. final boolean wasProvisioned = mProvisioned;
  255. final boolean isProvisioned = deviceIsProvisioned();
  256. // latch: never unprovision
  257. mProvisioned = wasProvisioned || isProvisioned;
  258. if (MORE_DEBUG) {
  259. Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
  260. + " is=" + isProvisioned + " now=" + mProvisioned);
  261. }
  262. synchronized (mQueueLock) {
  263. if (mProvisioned && !wasProvisioned && mEnabled) {
  264. // we're now good to go, so start the backup alarms
  265. if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
  266. startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
  267. }
  268. }
  269. }
  270. }
  271. class RestoreGetSetsParams {
  272. public IBackupTransport transport;
  273. public ActiveRestoreSession session;
  274. public IRestoreObserver observer;
  275. RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
  276. IRestoreObserver _observer) {
  277. transport = _transport;
  278. session = _session;
  279. observer = _observer;
  280. }
  281. }
  282. class RestoreParams {
  283. public IBackupTransport transport;
  284. public String dirName;
  285. public IRestoreObserver observer;
  286. public long token;
  287. public PackageInfo pkgInfo;
  288. public int pmToken; // in post-install restore, the PM's token for this transaction
  289. public boolean needFullBackup;
  290. public String[] filterSet;
  291. RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
  292. long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
  293. transport = _transport;
  294. dirName = _dirName;
  295. observer = _obs;
  296. token = _token;
  297. pkgInfo = _pkg;
  298. pmToken = _pmToken;
  299. needFullBackup = _needFullBackup;
  300. filterSet = null;
  301. }
  302. RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
  303. long _token, boolean _needFullBackup) {
  304. transport = _transport;
  305. dirName = _dirName;
  306. observer = _obs;
  307. token = _token;
  308. pkgInfo = null;
  309. pmToken = 0;
  310. needFullBackup = _needFullBackup;
  311. filterSet = null;
  312. }
  313. RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
  314. long _token, String[] _filterSet, boolean _needFullBackup) {
  315. transport = _transport;
  316. dirName = _dirName;
  317. observer = _obs;
  318. token = _token;
  319. pkgInfo = null;
  320. pmToken = 0;
  321. needFullBackup = _needFullBackup;
  322. filterSet = _filterSet;
  323. }
  324. }
  325. class ClearParams {
  326. public IBackupTransport transport;
  327. public PackageInfo packageInfo;
  328. ClearParams(IBackupTransport _transport, PackageInfo _info) {
  329. transport = _transport;
  330. packageInfo = _info;
  331. }
  332. }
  333. class ClearRetryParams {
  334. public String transportName;
  335. public String packageName;
  336. ClearRetryParams(String transport, String pkg) {
  337. transportName = transport;
  338. packageName = pkg;
  339. }
  340. }
  341. class FullParams {
  342. public ParcelFileDescriptor fd;
  343. public final AtomicBoolean latch;
  344. public IFullBackupRestoreObserver observer;
  345. public String curPassword; // filled in by the confirmation step
  346. public String encryptPassword;
  347. FullParams() {
  348. latch = new AtomicBoolean(false);
  349. }
  350. }
  351. class FullBackupParams extends FullParams {
  352. public boolean includeApks;
  353. public boolean includeObbs;
  354. public boolean includeShared;
  355. public boolean allApps;
  356. public boolean includeSystem;
  357. public String[] packages;
  358. FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
  359. boolean saveShared, boolean doAllApps, boolean doSystem, String[] pkgList) {
  360. fd = output;
  361. includeApks = saveApks;
  362. includeObbs = saveObbs;
  363. includeShared = saveShared;
  364. allApps = doAllApps;
  365. includeSystem = doSystem;
  366. packages = pkgList;
  367. }
  368. }
  369. class FullRestoreParams extends FullParams {
  370. FullRestoreParams(ParcelFileDescriptor input) {
  371. fd = input;
  372. }
  373. }
  374. // Bookkeeping of in-flight operations for timeout etc. purposes. The operation
  375. // token is the index of the entry in the pending-operations list.
  376. static final int OP_PENDING = 0;
  377. static final int OP_ACKNOWLEDGED = 1;
  378. static final int OP_TIMEOUT = -1;
  379. class Operation {
  380. public int state;
  381. public BackupRestoreTask callback;
  382. Operation(int initialState, BackupRestoreTask callbackObj) {
  383. state = initialState;
  384. callback = callbackObj;
  385. }
  386. }
  387. final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>();
  388. final Object mCurrentOpLock = new Object();
  389. final Random mTokenGenerator = new Random();
  390. final SparseArray<FullParams> mFullConfirmations = new SparseArray<FullParams>();
  391. // Where we keep our journal files and other bookkeeping
  392. File mBaseStateDir;
  393. File mDataDir;
  394. File mJournalDir;
  395. File mJournal;
  396. // Backup password, if any, and the file where it's saved. What is stored is not the
  397. // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
  398. // persisted) salt. Validation is performed by running the challenge text through the
  399. // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
  400. // the saved hash string, then the challenge text matches the originally supplied
  401. // password text.
  402. private final SecureRandom mRng = new SecureRandom();
  403. private String mPasswordHash;
  404. private File mPasswordHashFile;
  405. private int mPasswordVersion;
  406. private File mPasswordVersionFile;
  407. private byte[] mPasswordSalt;
  408. // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
  409. static final int PBKDF2_HASH_ROUNDS = 10000;
  410. static final int PBKDF2_KEY_SIZE = 256; // bits
  411. static final int PBKDF2_SALT_SIZE = 512; // bits
  412. static final String ENCRYPTION_ALGORITHM_NAME = "AES-256";
  413. // Keep a log of all the apps we've ever backed up, and what the
  414. // dataset tokens are for both the current backup dataset and
  415. // the ancestral dataset.
  416. private File mEverStored;
  417. HashSet<String> mEverStoredApps = new HashSet<String>();
  418. static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes
  419. File mTokenFile;
  420. Set<String> mAncestralPackages = null;
  421. long mAncestralToken = 0;
  422. long mCurrentToken = 0;
  423. // Persistently track the need to do a full init
  424. static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
  425. HashSet<String> mPendingInits = new HashSet<String>(); // transport names
  426. // Utility: build a new random integer token
  427. int generateToken() {
  428. int token;
  429. do {
  430. synchronized (mTokenGenerator) {
  431. token = mTokenGenerator.nextInt();
  432. }
  433. } while (token < 0);
  434. return token;
  435. }
  436. // ----- Asynchronous backup/restore handler thread -----
  437. private class BackupHandler extends Handler {
  438. public BackupHandler(Looper looper) {
  439. super(looper);
  440. }
  441. public void handleMessage(Message msg) {
  442. switch (msg.what) {
  443. case MSG_RUN_BACKUP:
  444. {
  445. mLastBackupPass = System.currentTimeMillis();
  446. mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
  447. IBackupTransport transport = getTransport(mCurrentTransport);
  448. if (transport == null) {
  449. Slog.v(TAG, "Backup requested but no transport available");
  450. synchronized (mQueueLock) {
  451. mBackupRunning = false;
  452. }
  453. mWakelock.release();
  454. break;
  455. }
  456. // snapshot the pending-backup set and work on that
  457. ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
  458. File oldJournal = mJournal;
  459. synchronized (mQueueLock) {
  460. // Do we have any work to do? Construct the work queue
  461. // then release the synchronization lock to actually run
  462. // the backup.
  463. if (mPendingBackups.size() > 0) {
  464. for (BackupRequest b: mPendingBackups.values()) {
  465. queue.add(b);
  466. }
  467. if (DEBUG) Slog.v(TAG, "clearing pending backups");
  468. mPendingBackups.clear();
  469. // Start a new backup-queue journal file too
  470. mJournal = null;
  471. }
  472. }
  473. // At this point, we have started a new journal file, and the old
  474. // file identity is being passed to the backup processing task.
  475. // When it completes successfully, that old journal file will be
  476. // deleted. If we crash prior to that, the old journal is parsed
  477. // at next boot and the journaled requests fulfilled.
  478. boolean staged = true;
  479. if (queue.size() > 0) {
  480. // Spin up a backup state sequence and set it running
  481. try {
  482. String dirName = transport.transportDirName();
  483. PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
  484. queue, oldJournal);
  485. Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
  486. sendMessage(pbtMessage);
  487. } catch (RemoteException e) {
  488. // unable to ask the transport its dir name -- transient failure, since
  489. // the above check succeeded. Try again next time.
  490. Slog.e(TAG, "Transport became unavailable attempting backup");
  491. staged = false;
  492. }
  493. } else {
  494. Slog.v(TAG, "Backup requested but nothing pending");
  495. staged = false;
  496. }
  497. if (!staged) {
  498. // if we didn't actually hand off the wakelock, rewind until next time
  499. synchronized (mQueueLock) {
  500. mBackupRunning = false;
  501. }
  502. mWakelock.release();
  503. }
  504. break;
  505. }
  506. case MSG_BACKUP_RESTORE_STEP:
  507. {
  508. try {
  509. BackupRestoreTask task = (BackupRestoreTask) msg.obj;
  510. if (MORE_DEBUG) Slog.v(TAG, "Got next step for " + task + ", executing");
  511. task.execute();
  512. } catch (ClassCastException e) {
  513. Slog.e(TAG, "Invalid backup task in flight, obj=" + msg.obj);
  514. }
  515. break;
  516. }
  517. case MSG_OP_COMPLETE:
  518. {
  519. try {
  520. BackupRestoreTask task = (BackupRestoreTask) msg.obj;
  521. task.operationComplete();
  522. } catch (ClassCastException e) {
  523. Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj);
  524. }
  525. break;
  526. }
  527. case MSG_RUN_FULL_BACKUP:
  528. {
  529. // TODO: refactor full backup to be a looper-based state machine
  530. // similar to normal backup/restore.
  531. FullBackupParams params = (FullBackupParams)msg.obj;
  532. PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
  533. params.observer, params.includeApks, params.includeObbs,
  534. params.includeShared, params.curPassword, params.encryptPassword,
  535. params.allApps, params.includeSystem, params.packages, params.latch);
  536. (new Thread(task)).start();
  537. break;
  538. }
  539. case MSG_RUN_RESTORE:
  540. {
  541. RestoreParams params = (RestoreParams)msg.obj;
  542. Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
  543. PerformRestoreTask task = new PerformRestoreTask(
  544. params.transport, params.dirName, params.observer,
  545. params.token, params.pkgInfo, params.pmToken,
  546. params.needFullBackup, params.filterSet);
  547. Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
  548. sendMessage(restoreMsg);
  549. break;
  550. }
  551. case MSG_RUN_FULL_RESTORE:
  552. {
  553. // TODO: refactor full restore to be a looper-based state machine
  554. // similar to normal backup/restore.
  555. FullRestoreParams params = (FullRestoreParams)msg.obj;
  556. PerformFullRestoreTask task = new PerformFullRestoreTask(params.fd,
  557. params.curPassword, params.encryptPassword,
  558. params.observer, params.latch);
  559. (new Thread(task)).start();
  560. break;
  561. }
  562. case MSG_RUN_CLEAR:
  563. {
  564. ClearParams params = (ClearParams)msg.obj;
  565. (new PerformClearTask(params.transport, params.packageInfo)).run();
  566. break;
  567. }
  568. case MSG_RETRY_CLEAR:
  569. {
  570. // reenqueues if the transport remains unavailable
  571. ClearRetryParams params = (ClearRetryParams)msg.obj;
  572. clearBackupData(params.transportName, params.packageName);
  573. break;
  574. }
  575. case MSG_RUN_INITIALIZE:
  576. {
  577. HashSet<String> queue;
  578. // Snapshot the pending-init queue and work on that
  579. synchronized (mQueueLock) {
  580. queue = new HashSet<String>(mPendingInits);
  581. mPendingInits.clear();
  582. }
  583. (new PerformInitializeTask(queue)).run();
  584. break;
  585. }
  586. case MSG_RETRY_INIT:
  587. {
  588. synchronized (mQueueLock) {
  589. recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
  590. mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
  591. mRunInitIntent);
  592. }
  593. break;
  594. }
  595. case MSG_RUN_GET_RESTORE_SETS:
  596. {
  597. // Like other async operations, this is entered with the wakelock held
  598. RestoreSet[] sets = null;
  599. RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
  600. try {
  601. sets = params.transport.getAvailableRestoreSets();
  602. // cache the result in the active session
  603. synchronized (params.session) {
  604. params.session.mRestoreSets = sets;
  605. }
  606. if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  607. } catch (Exception e) {
  608. Slog.e(TAG, "Error from transport getting set list");
  609. } finally {
  610. if (params.observer != null) {
  611. try {
  612. params.observer.restoreSetsAvailable(sets);
  613. } catch (RemoteException re) {
  614. Slog.e(TAG, "Unable to report listing to observer");
  615. } catch (Exception e) {
  616. Slog.e(TAG, "Restore observer threw", e);
  617. }
  618. }
  619. // Done: reset the session timeout clock
  620. removeMessages(MSG_RESTORE_TIMEOUT);
  621. sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
  622. mWakelock.release();
  623. }
  624. break;
  625. }
  626. case MSG_TIMEOUT:
  627. {
  628. handleTimeout(msg.arg1, msg.obj);
  629. break;
  630. }
  631. case MSG_RESTORE_TIMEOUT:
  632. {
  633. synchronized (BackupManagerService.this) {
  634. if (mActiveRestoreSession != null) {
  635. // Client app left the restore session dangling. We know that it
  636. // can't be in the middle of an actual restore operation because
  637. // the timeout is suspended while a restore is in progress. Clean
  638. // up now.
  639. Slog.w(TAG, "Restore session timed out; aborting");
  640. post(mActiveRestoreSession.new EndRestoreRunnable(
  641. BackupManagerService.this, mActiveRestoreSession));
  642. }
  643. }
  644. }
  645. case MSG_FULL_CONFIRMATION_TIMEOUT:
  646. {
  647. synchronized (mFullConfirmations) {
  648. FullParams params = mFullConfirmations.get(msg.arg1);
  649. if (params != null) {
  650. Slog.i(TAG, "Full backup/restore timed out waiting for user confirmation");
  651. // Release the waiter; timeout == completion
  652. signalFullBackupRestoreCompletion(params);
  653. // Remove the token from the set
  654. mFullConfirmations.delete(msg.arg1);
  655. // Report a timeout to the observer, if any
  656. if (params.observer != null) {
  657. try {
  658. params.observer.onTimeout();
  659. } catch (RemoteException e) {
  660. /* don't care if the app has gone away */
  661. }
  662. }
  663. } else {
  664. Slog.d(TAG, "couldn't find params for token " + msg.arg1);
  665. }
  666. }
  667. break;
  668. }
  669. }
  670. }
  671. }
  672. // ----- Debug-only backup operation trace -----
  673. void addBackupTrace(String s) {
  674. if (DEBUG_BACKUP_TRACE) {
  675. synchronized (mBackupTrace) {
  676. mBackupTrace.add(s);
  677. }
  678. }
  679. }
  680. void clearBackupTrace() {
  681. if (DEBUG_BACKUP_TRACE) {
  682. synchronized (mBackupTrace) {
  683. mBackupTrace.clear();
  684. }
  685. }
  686. }
  687. // ----- Main service implementation -----
  688. public BackupManagerService(Context context) {
  689. mContext = context;
  690. mPackageManager = context.getPackageManager();
  691. mPackageManagerBinder = AppGlobals.getPackageManager();
  692. mActivityManager = ActivityManagerNative.getDefault();
  693. mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
  694. mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
  695. mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
  696. mBackupManagerBinder = asInterface(asBinder());
  697. // spin up the backup/restore handler thread
  698. mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
  699. mHandlerThread.start();
  700. mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
  701. // Set up our bookkeeping
  702. final ContentResolver resolver = context.getContentResolver();
  703. boolean areEnabled = Settings.Secure.getInt(resolver,
  704. Settings.Secure.BACKUP_ENABLED, 0) != 0;
  705. mProvisioned = Settings.Global.getInt(resolver,
  706. Settings.Global.DEVICE_PROVISIONED, 0) != 0;
  707. mAutoRestore = Settings.Secure.getInt(resolver,
  708. Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
  709. mProvisionedObserver = new ProvisionedObserver(mBackupHandler);
  710. resolver.registerContentObserver(
  711. Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
  712. false, mProvisionedObserver);
  713. // If Encrypted file systems is enabled or disabled, this call will return the
  714. // correct directory.
  715. mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
  716. mBaseStateDir.mkdirs();
  717. if (!SELinux.restorecon(mBaseStateDir)) {
  718. Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
  719. }
  720. mDataDir = Environment.getDownloadCacheDirectory();
  721. mPasswordVersion = 1; // unless we hear otherwise
  722. mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
  723. if (mPasswordVersionFile.exists()) {
  724. FileInputStream fin = null;
  725. DataInputStream in = null;
  726. try {
  727. fin = new FileInputStream(mPasswordVersionFile);
  728. in = new DataInputStream(fin);
  729. mPasswordVersion = in.readInt();
  730. } catch (IOException e) {
  731. Slog.e(TAG, "Unable to read backup pw version");
  732. } finally {
  733. try {
  734. if (in != null) in.close();
  735. if (fin != null) fin.close();
  736. } catch (IOException e) {
  737. Slog.w(TAG, "Error closing pw version files");
  738. }
  739. }
  740. }
  741. mPasswordHashFile = new File(mBaseStateDir, "pwhash");
  742. if (mPasswordHashFile.exists()) {
  743. FileInputStream fin = null;
  744. DataInputStream in = null;
  745. try {
  746. fin = new FileInputStream(mPasswordHashFile);
  747. in = new DataInputStream(new BufferedInputStream(fin));
  748. // integer length of the salt array, followed by the salt,
  749. // then the hex pw hash string
  750. int saltLen = in.readInt();
  751. byte[] salt = new byte[saltLen];
  752. in.readFully(salt);
  753. mPasswordHash = in.readUTF();
  754. mPasswordSalt = salt;
  755. } catch (IOException e) {
  756. Slog.e(TAG, "Unable to read saved backup pw hash");
  757. } finally {
  758. try {
  759. if (in != null) in.close();
  760. if (fin != null) fin.close();
  761. } catch (IOException e) {
  762. Slog.w(TAG, "Unable to close streams");
  763. }
  764. }
  765. }
  766. // Alarm receivers for scheduled backups & initialization operations
  767. mRunBackupReceiver = new RunBackupReceiver();
  768. IntentFilter filter = new IntentFilter();
  769. filter.addAction(RUN_BACKUP_ACTION);
  770. context.registerReceiver(mRunBackupReceiver, filter,
  771. android.Manifest.permission.BACKUP, null);
  772. mRunInitReceiver = new RunInitializeReceiver();
  773. filter = new IntentFilter();
  774. filter.addAction(RUN_INITIALIZE_ACTION);
  775. context.registerReceiver(mRunInitReceiver, filter,
  776. android.Manifest.permission.BACKUP, null);
  777. Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
  778. backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
  779. mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
  780. Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
  781. backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
  782. mRunInitIntent = PendingIntent.getBroadcast(context, MSG_RUN_INITIALIZE, initIntent, 0);
  783. // Set up the backup-request journaling
  784. mJournalDir = new File(mBaseStateDir, "pending");
  785. mJournalDir.mkdirs(); // creates mBaseStateDir along the way
  786. mJournal = null; // will be created on first use
  787. // Set up the various sorts of package tracking we do
  788. initPackageTracking();
  789. // Build our mapping of uid to backup client services. This implicitly
  790. // schedules a backup pass on the Package Manager metadata the first
  791. // time anything needs to be backed up.
  792. synchronized (mBackupParticipants) {
  793. addPackageParticipantsLocked(null);
  794. }
  795. // Set up our transport options and initialize the default transport
  796. // TODO: Don't create transports that we don't need to?
  797. mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
  798. Settings.Secure.BACKUP_TRANSPORT);
  799. if ("".equals(mCurrentTransport)) {
  800. mCurrentTransport = null;
  801. }
  802. if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
  803. // Find transport hosts and bind to their services
  804. Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
  805. List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
  806. transportServiceIntent, 0, UserHandle.USER_OWNER);
  807. if (DEBUG) {
  808. Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
  809. }
  810. if (hosts != null) {
  811. if (MORE_DEBUG) {
  812. for (int i = 0; i < hosts.size(); i++) {
  813. ServiceInfo info = hosts.get(i).serviceInfo;
  814. Slog.v(TAG, " " + info.packageName + "/" + info.name);
  815. }
  816. }
  817. for (int i = 0; i < hosts.size(); i++) {
  818. try {
  819. ServiceInfo info = hosts.get(i).serviceInfo;
  820. PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
  821. if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
  822. ComponentName svcName = new ComponentName(info.packageName, info.name);
  823. if (DEBUG) {
  824. Slog.i(TAG, "Binding to transport host " + svcName);
  825. }
  826. Intent intent = new Intent(transportServiceIntent);
  827. intent.setComponent(svcName);
  828. TransportConnection connection = new TransportConnection();
  829. mTransportConnections.add(connection);
  830. context.bindServiceAsUser(intent,
  831. connection, Context.BIND_AUTO_CREATE,
  832. UserHandle.OWNER);
  833. } else {
  834. Slog.w(TAG, "Transport package not privileged: " + info.packageName);
  835. }
  836. } catch (Exception e) {
  837. Slog.e(TAG, "Problem resolving transport service: " + e.getMessage());
  838. }
  839. }
  840. }
  841. // Now that we know about valid backup participants, parse any
  842. // leftover journal files into the pending backup set
  843. parseLeftoverJournals();
  844. // Power management
  845. mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
  846. // Start the backup passes going
  847. setBackupEnabled(areEnabled);
  848. }
  849. private class RunBackupReceiver extends BroadcastReceiver {
  850. public void onReceive(Context context, Intent intent) {
  851. if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
  852. synchronized (mQueueLock) {
  853. if (mPendingInits.size() > 0) {
  854. // If there are pending init operations, we process those
  855. // and then settle into the usual periodic backup schedule.
  856. if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
  857. try {
  858. mAlarmManager.cancel(mRunInitIntent);
  859. mRunInitIntent.send();
  860. } catch (PendingIntent.CanceledException ce) {
  861. Slog.e(TAG, "Run init intent cancelled");
  862. // can't really do more than bail here
  863. }
  864. } else {
  865. // Don't run backups now if we're disabled or not yet
  866. // fully set up.
  867. if (mEnabled && mProvisioned) {
  868. if (!mBackupRunning) {
  869. if (DEBUG) Slog.v(TAG, "Running a backup pass");
  870. // Acquire the wakelock and pass it to the backup thread. it will
  871. // be released once backup concludes.
  872. mBackupRunning = true;
  873. mWakelock.acquire();
  874. Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
  875. mBackupHandler.sendMessage(msg);
  876. } else {
  877. Slog.i(TAG, "Backup time but one already running");
  878. }
  879. } else {
  880. Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
  881. }
  882. }
  883. }
  884. }
  885. }
  886. }
  887. private class RunInitializeReceiver extends BroadcastReceiver {
  888. public void onReceive(Context context, Intent intent) {
  889. if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
  890. synchronized (mQueueLock) {
  891. if (DEBUG) Slog.v(TAG, "Running a device init");
  892. // Acquire the wakelock and pass it to the init thread. it will
  893. // be released once init concludes.
  894. mWakelock.acquire();
  895. Message msg = mBackupHandler.obtainMessage(MSG_RUN_INITIALIZE);
  896. mBackupHandler.sendMessage(msg);
  897. }
  898. }
  899. }
  900. }
  901. private void initPackageTracking() {
  902. if (DEBUG) Slog.v(TAG, "Initializing package tracking");
  903. // Remember our ancestral dataset
  904. mTokenFile = new File(mBaseStateDir, "ancestral");
  905. try {
  906. RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
  907. int version = tf.readInt();
  908. if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
  909. mAncestralToken = tf.readLong();
  910. mCurrentToken = tf.readLong();
  911. int numPackages = tf.readInt();
  912. if (numPackages >= 0) {
  913. mAncestralPackages = new HashSet<String>();
  914. for (int i = 0; i < numPackages; i++) {
  915. String pkgName = tf.readUTF();
  916. mAncestralPackages.add(pkgName);
  917. }
  918. }
  919. }
  920. tf.close();
  921. } catch (FileNotFoundException fnf) {
  922. // Probably innocuous
  923. Slog.v(TAG, "No ancestral data");
  924. } catch (IOException e) {
  925. Slog.w(TAG, "Unable to read token file", e);
  926. }
  927. // Keep a log of what apps we've ever backed up. Because we might have
  928. // rebooted in the middle of an operation that was removing something from
  929. // this log, we sanity-check its contents here and reconstruct it.
  930. mEverStored = new File(mBaseStateDir, "processed");
  931. File tempProcessedFile = new File(mBaseStateDir, "processed.new");
  932. // If we were in the middle of removing something from the ever-backed-up
  933. // file, there might be a transient "processed.new" file still present.
  934. // Ignore it -- we'll validate "processed" against the current package set.
  935. if (tempProcessedFile.exists()) {
  936. tempProcessedFile.delete();
  937. }
  938. // If there are previous contents, parse them out then start a new
  939. // file to continue the recordkeeping.
  940. if (mEverStored.exists()) {
  941. RandomAccessFile temp = null;
  942. RandomAccessFile in = null;
  943. try {
  944. temp = new RandomAccessFile(tempProcessedFile, "rws");
  945. in = new RandomAccessFile(mEverStored, "r");
  946. while (true) {
  947. PackageInfo info;
  948. String pkg = in.readUTF();
  949. try {
  950. info = mPackageManager.getPackageInfo(pkg, 0);
  951. mEverStoredApps.add(pkg);
  952. temp.writeUTF(pkg);
  953. if (MORE_DEBUG) Slog.v(TAG, " + " + pkg);
  954. } catch (NameNotFoundException e) {
  955. // nope, this package was uninstalled; don't include it
  956. if (MORE_DEBUG) Slog.v(TAG, " - " + pkg);
  957. }
  958. }
  959. } catch (EOFException e) {
  960. // Once we've rewritten the backup history log, atomically replace the
  961. // old one with the new one then reopen the file for continuing use.
  962. if (!tempProcessedFile.renameTo(mEverStored)) {
  963. Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
  964. }
  965. } catch (IOException e) {
  966. Slog.e(TAG, "Error in processed file", e);
  967. } finally {
  968. try { if (temp != null) temp.close(); } catch (IOException e) {}
  969. try { if (in != null) in.close(); } catch (IOException e) {}
  970. }
  971. }
  972. // Register for broadcasts about package install, etc., so we can
  973. // update the provider list.
  974. IntentFilter filter = new IntentFilter();
  975. filter.addAction(Intent.ACTION_PACKAGE_ADDED);
  976. filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
  977. filter.addDataScheme("package");
  978. mContext.registerReceiver(mBroadcastReceiver, filter);
  979. // Register for events related to sdcard installation.
  980. IntentFilter sdFilter = new IntentFilter();
  981. sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
  982. sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
  983. mContext.registerReceiver(mBroadcastReceiver, sdFilter);
  984. }
  985. private void parseLeftoverJournals() {
  986. for (File f : mJournalDir.listFiles()) {
  987. if (mJournal == null || f.compareTo(mJournal) != 0) {
  988. // This isn't the current journal, so it must be a leftover. Read
  989. // out the package names mentioned there and schedule them for
  990. // backup.
  991. RandomAccessFile in = null;
  992. try {
  993. Slog.i(TAG, "Found stale backup journal, scheduling");
  994. in = new RandomAccessFile(f, "r");
  995. while (true) {
  996. String packageName = in.readUTF();
  997. Slog.i(TAG, " " + packageName);
  998. dataChangedImpl(packageName);
  999. }
  1000. } catch (EOFException e) {
  1001. // no more data; we're done
  1002. } catch (Exception e) {
  1003. Slog.e(TAG, "Can't read " + f, e);
  1004. } finally {
  1005. // close/delete the file
  1006. try { if (in != null) in.close(); } catch (IOException e) {}
  1007. f.delete();
  1008. }
  1009. }
  1010. }
  1011. }
  1012. private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) {
  1013. return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds);
  1014. }
  1015. private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) {
  1016. try {
  1017. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
  1018. KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
  1019. return keyFactory.generateSecret(ks);
  1020. } catch (InvalidKeySpecException e) {
  1021. Slog.e(TAG, "Invalid key spec for PBKDF2!");
  1022. } catch (NoSuchAlgorithmException e) {
  1023. Slog.e(TAG, "PBKDF2 unavailable!");
  1024. }
  1025. return null;
  1026. }
  1027. private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) {
  1028. SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds);
  1029. if (key != null) {
  1030. return byteArrayToHex(key.getEncoded());
  1031. }
  1032. return null;
  1033. }
  1034. private String byteArrayToHex(byte[] data) {
  1035. StringBuilder buf = new StringBuilder(data.length * 2);
  1036. for (int i = 0; i < data.length; i++) {
  1037. buf.append(Byte.toHexString(data[i], true));
  1038. }
  1039. return buf.toString();
  1040. }
  1041. private byte[] hexToByteArray(String digits) {
  1042. final int bytes = digits.length() / 2;
  1043. if (2*bytes != digits.length()) {
  1044. throw new IllegalArgumentException("Hex string must have an even number of digits");
  1045. }
  1046. byte[] result = new byte[bytes];
  1047. for (int i = 0; i < digits.length(); i += 2) {
  1048. result[i/2] = (byte) Integer.parseInt(digits.substring(i, i+2), 16);
  1049. }
  1050. return result;
  1051. }
  1052. private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) {
  1053. char[] mkAsChar = new char[pwBytes.length];
  1054. for (int i = 0; i < pwBytes.length; i++) {
  1055. mkAsChar[i] = (char) pwBytes[i];
  1056. }
  1057. Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);
  1058. return checksum.getEncoded();
  1059. }
  1060. // Used for generating random salts or passwords
  1061. private byte[] randomBytes(int bits) {
  1062. byte[] array = new byte[bits / 8];
  1063. mRng.nextBytes(array);
  1064. return array;
  1065. }
  1066. // Backup password management
  1067. boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
  1068. // First, on an encrypted device we require matching the device pw
  1069. final boolean isEncrypted;
  1070. try {
  1071. isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
  1072. if (isEncrypted) {
  1073. if (DEBUG) {
  1074. Slog.i(TAG, "Device encrypted; verifying against device data pw");
  1075. }
  1076. // 0 means the password validated
  1077. // -2 means device not encrypted
  1078. // Any other result is either password failure or an error condition,
  1079. // so we refuse the match
  1080. final int result = mMountService.verifyEncryptionPassword(candidatePw);
  1081. if (result == 0) {
  1082. if (MORE_DEBUG) Slog.d(TAG, "Pw verifies");
  1083. return true;
  1084. } else if (result != -2) {
  1085. if (MORE_DEBUG) Slog.d(TAG, "Pw mismatch");
  1086. return false;
  1087. } else {
  1088. // ...else the device is supposedly not encrypted. HOWEVER, the
  1089. // query about the encryption state said that the device *is*
  1090. // encrypted, so ... we may have a problem. Log it and refuse
  1091. // the backup.
  1092. Slog.e(TAG, "verified encryption state mismatch against query; no match allowed");
  1093. return false;
  1094. }
  1095. }
  1096. } catch (Exception e) {
  1097. // Something went wrong talking to the mount service. This is very bad;
  1098. // assume that we fail password validation.
  1099. return false;
  1100. }
  1101. if (mPasswordHash == null) {
  1102. // no current password case -- require that 'currentPw' be null or empty
  1103. if (candidatePw == null || "".equals(candidatePw)) {
  1104. return true;
  1105. } // else the non-empty candidate does not match the empty stored pw
  1106. } else {
  1107. // hash the stated current pw and compare to the stored one
  1108. if (candidatePw != null && candidatePw.length() > 0) {
  1109. String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds);
  1110. if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
  1111. // candidate hash matches the stored hash -- the password matches
  1112. return true;
  1113. }
  1114. } // else the stored pw is nonempty but the candidate is empty; no match
  1115. }
  1116. return false;
  1117. }
  1118. @Override
  1119. public boolean setBackupPassword(String currentPw, String newPw) {
  1120. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  1121. "setBackupPassword");
  1122. // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes
  1123. final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
  1124. // If the supplied pw doesn't hash to the the saved one, fail. The password
  1125. // might be caught in the legacy crypto mismatch; verify that too.
  1126. if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
  1127. && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
  1128. currentPw, PBKDF2_HASH_ROUNDS))) {
  1129. return false;
  1130. }
  1131. // Snap up to current on the pw file version
  1132. mPasswordVersion = BACKUP_PW_FILE_VERSION;
  1133. FileOutputStream pwFout = null;
  1134. DataOutputStream pwOut = null;
  1135. try {
  1136. pwFout = new FileOutputStream(mPasswordVersionFile);
  1137. pwOut = new DataOutputStream(pwFout);
  1138. pwOut.writeInt(mPasswordVersion);
  1139. } catch (IOException e) {
  1140. Slog.e(TAG, "Unable to write backup pw version; password not changed");
  1141. return false;
  1142. } finally {
  1143. try {
  1144. if (pwOut != null) pwOut.close();
  1145. if (pwFout != null) pwFout.close();
  1146. } catch (IOException e) {
  1147. Slog.w(TAG, "Unable to close pw version record");
  1148. }
  1149. }
  1150. // Clearing the password is okay
  1151. if (newPw == null || newPw.isEmpty()) {
  1152. if (mPasswordHashFile.exists()) {
  1153. if (!mPasswordHashFile.delete()) {
  1154. // Unable to delete the old pw file, so fail
  1155. Slog.e(TAG, "Unable to clear backup password");
  1156. return false;
  1157. }
  1158. }
  1159. mPasswordHash = null;
  1160. mPasswordSalt = null;
  1161. return true;
  1162. }
  1163. try {
  1164. // Okay, build the hash of the new backup password
  1165. byte[] salt = randomBytes(PBKDF2_SALT_SIZE);
  1166. String newPwHash = buildPasswordHash(PBKDF_CURRENT, newPw, salt, PBKDF2_HASH_ROUNDS);
  1167. OutputStream pwf = null, buffer = null;
  1168. DataOutputStream out = null;
  1169. try {
  1170. pwf = new FileOutputStream(mPasswordHashFile);
  1171. buffer = new BufferedOutputStream(pwf);
  1172. out = new DataOutputStream(buffer);
  1173. // integer length of the salt array, followed by the salt,
  1174. // then the hex pw hash string
  1175. out.writeInt(salt.length);
  1176. out.write(salt);
  1177. out.writeUTF(newPwHash);
  1178. out.flush();
  1179. mPasswordHash = newPwHash;
  1180. mPasswordSalt = salt;
  1181. return true;
  1182. } finally {
  1183. if (out != null) out.close();
  1184. if (buffer != null) buffer.close();
  1185. if (pwf != null) pwf.close();
  1186. }
  1187. } catch (IOException e) {
  1188. Slog.e(TAG, "Unable to set backup password");
  1189. }
  1190. return false;
  1191. }
  1192. @Override
  1193. public boolean hasBackupPassword() {
  1194. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  1195. "hasBackupPassword");
  1196. try {
  1197. return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE)
  1198. || (mPasswordHash != null && mPasswordHash.length() > 0);
  1199. } catch (Exception e) {
  1200. // If we can't talk to the mount service we have a serious problem; fail
  1201. // "secure" i.e. assuming that we require a password
  1202. return true;
  1203. }
  1204. }
  1205. private boolean backupPasswordMatches(String currentPw) {
  1206. if (hasBackupPassword()) {
  1207. final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
  1208. if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
  1209. && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
  1210. currentPw, PBKDF2_HASH_ROUNDS))) {
  1211. if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
  1212. return false;
  1213. }
  1214. }
  1215. return true;
  1216. }
  1217. // Maintain persistent state around whether need to do an initialize operation.
  1218. // Must be called with the queue lock held.
  1219. void recordInitPendingLocked(boolean isPending, String transportName) {
  1220. if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
  1221. + " on transport " + transportName);
  1222. mBackupHandler.removeMessages(MSG_RETRY_INIT);
  1223. try {
  1224. IBackupTransport transport = getTransport(transportName);
  1225. if (transport != null) {
  1226. String transportDirName = transport.transportDirName();
  1227. File stateDir = new File(mBaseStateDir, transportDirName);
  1228. File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
  1229. if (isPending) {
  1230. // We need an init before we can proceed with sending backup data.
  1231. // Record that with an entry in our set of pending inits, as well as
  1232. // journaling it via creation of a sentinel file.
  1233. mPendingInits.add(transportName);
  1234. try {
  1235. (new FileOutputStream(initPendingFile)).close();
  1236. } catch (IOException ioe) {
  1237. // Something is badly wrong with our permissions; just try to move on
  1238. }
  1239. } else {
  1240. // No more initialization needed; wipe the journal and reset our state.
  1241. initPendingFile.delete();
  1242. mPendingInits.remove(transportName);
  1243. }
  1244. return; // done; don't fall through to the error case
  1245. }
  1246. } catch (RemoteException e) {
  1247. // transport threw when asked its name; fall through to the lookup-failed case
  1248. }
  1249. // The named transport doesn't exist or threw. This operation is
  1250. // important, so we record the need for a an init and post a message
  1251. // to retry the init later.
  1252. if (isPending) {
  1253. mPendingInits.add(transportName);
  1254. mBackupHandler.sendMessageDelayed(
  1255. mBackupHandler.obtainMessage(MSG_RETRY_INIT,
  1256. (isPending ? 1 : 0),
  1257. 0,
  1258. transportName),
  1259. TRANSPORT_RETRY_INTERVAL);
  1260. }
  1261. }
  1262. // Reset all of our bookkeeping, in response to having been told that
  1263. // the backend data has been wiped [due to idle expiry, for example],
  1264. // so we must re-upload all saved settings.
  1265. void resetBackupState(File stateFileDir) {
  1266. synchronized (mQueueLock) {
  1267. // Wipe the "what we've ever backed up" tracking
  1268. mEverStoredApps.clear();
  1269. mEverStored.delete();
  1270. mCurrentToken = 0;
  1271. writeRestoreTokens();
  1272. // Remove all the state files
  1273. for (File sf : stateFileDir.listFiles()) {
  1274. // ... but don't touch the needs-init sentinel
  1275. if (!sf.getName().equals(INIT_SENTINEL_FILE_NAME)) {
  1276. sf.delete();
  1277. }
  1278. }
  1279. }
  1280. // Enqueue a new backup of every participant
  1281. synchronized (mBackupParticipants) {
  1282. final int N = mBackupParticipants.size();
  1283. for (int i=0; i<N; i++) {
  1284. HashSet<String> participants = mBackupParticipants.valueAt(i);
  1285. if (participants != null) {
  1286. for (String packageName : participants) {
  1287. dataChangedImpl(packageName);
  1288. }
  1289. }
  1290. }
  1291. }
  1292. }
  1293. // Add a transport to our set of available backends. If 'transport' is null, this
  1294. // is an unregistration, and the transport's entry is removed from our bookkeeping.
  1295. private void registerTransport(String name, String component, IBackupTransport transport) {
  1296. synchronized (mTransports) {
  1297. if (DEBUG) Slog.v(TAG, "Registering transport "
  1298. + component + "::" + name + " = " + transport);
  1299. if (transport != null) {
  1300. mTransports.put(name, transport);
  1301. mTransportNames.put(component, name);
  1302. } else {
  1303. mTransports.remove(mTransportNames.get(component));
  1304. mTransportNames.remove(component);
  1305. // Nothing further to do in the unregistration case
  1306. return;
  1307. }
  1308. }
  1309. // If the init sentinel file exists, we need to be sure to perform the init
  1310. // as soon as practical. We also create the state directory at registration
  1311. // time to ensure it's present from the outset.
  1312. try {
  1313. String transportName = transport.transportDirName();
  1314. File stateDir = new File(mBaseStateDir, transportName);
  1315. stateDir.mkdirs();
  1316. File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
  1317. if (initSentinel.exists()) {
  1318. synchronized (mQueueLock) {
  1319. mPendingInits.add(transportName);
  1320. // TODO: pick a better starting time than now + 1 minute
  1321. long delay = 1000 * 60; // one minute, in milliseconds
  1322. mAlarmManager.set(AlarmManager.RTC_WAKEUP,
  1323. System.currentTimeMillis() + delay, mRunInitIntent);
  1324. }
  1325. }
  1326. } catch (RemoteException e) {
  1327. // the transport threw when asked its file naming prefs; declare it invalid
  1328. Slog.e(TAG, "Unable to register transport as " + name);
  1329. mTransportNames.remove(component);
  1330. mTransports.remove(name);
  1331. }
  1332. }
  1333. // ----- Track installation/removal of packages -----
  1334. BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
  1335. public void onReceive(Context context, Intent intent) {
  1336. if (DEBUG) Slog.d(TAG, "Received broadcast " + intent);
  1337. String action = intent.getAction();
  1338. boolean replacing = false;
  1339. boolean added = false;
  1340. Bundle extras = intent.getExtras();
  1341. String pkgList[] = null;
  1342. if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
  1343. Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
  1344. Uri uri = intent.getData();
  1345. if (uri == null) {
  1346. return;
  1347. }
  1348. String pkgName = uri.getSchemeSpecificPart();
  1349. if (pkgName != null) {
  1350. pkgList = new String[] { pkgName };
  1351. }
  1352. added = Intent.ACTION_PACKAGE_ADDED.equals(action);
  1353. replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
  1354. } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
  1355. added = true;
  1356. pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
  1357. } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
  1358. added = false;
  1359. pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
  1360. }
  1361. if (pkgList == null || pkgList.length == 0) {
  1362. return;
  1363. }
  1364. final int uid = extras.getInt(Intent.EXTRA_UID);
  1365. if (added) {
  1366. synchronized (mBackupParticipants) {
  1367. if (replacing) {
  1368. // This is the package-replaced case; we just remove the entry
  1369. // under the old uid and fall through to re-add.
  1370. removePackageParticipantsLocked(pkgList, uid);
  1371. }
  1372. addPackageParticipantsLocked(pkgList);
  1373. }
  1374. } else {
  1375. if (replacing) {
  1376. // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
  1377. } else {
  1378. synchronized (mBackupParticipants) {
  1379. removePackageParticipantsLocked(pkgList, uid);
  1380. }
  1381. }
  1382. }
  1383. }
  1384. };
  1385. // ----- Track connection to transports service -----
  1386. class TransportConnection implements ServiceConnection {
  1387. @Override
  1388. public void onServiceConnected(ComponentName component, IBinder service) {
  1389. if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
  1390. try {
  1391. IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
  1392. registerTransport(transport.name(), component.flattenToShortString(), transport);
  1393. } catch (RemoteException e) {
  1394. Slog.e(TAG, "Unable to register transport " + component);
  1395. }
  1396. }
  1397. @Override
  1398. public void onServiceDisconnected(ComponentName component) {
  1399. if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
  1400. registerTransport(null, component.flattenToShortString(), null);
  1401. }
  1402. };
  1403. // Add the backup agents in the given packages to our set of known backup participants.
  1404. // If 'packageNames' is null, adds all backup agents in the whole system.
  1405. void addPackageParticipantsLocked(String[] packageNames) {
  1406. // Look for apps that define the android:backupAgent attribute
  1407. List<PackageInfo> targetApps = allAgentPackages();
  1408. if (packageNames != null) {
  1409. if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length);
  1410. for (String packageName : packageNames) {
  1411. addPackageParticipantsLockedInner(packageName, targetApps);
  1412. }
  1413. } else {
  1414. if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all");
  1415. addPackageParticipantsLockedInner(null, targetApps);
  1416. }
  1417. }
  1418. private void addPackageParticipantsLockedInner(String packageName,
  1419. List<PackageInfo> targetPkgs) {
  1420. if (MORE_DEBUG) {
  1421. Slog.v(TAG, "Examining " + packageName + " for backup agent");
  1422. }
  1423. for (PackageInfo pkg : targetPkgs) {
  1424. if (packageName == null || pkg.packageName.equals(packageName)) {
  1425. int uid = pkg.applicationInfo.uid;
  1426. HashSet<String> set = mBackupParticipants.get(uid);
  1427. if (set == null) {
  1428. set = new HashSet<String>();
  1429. mBackupParticipants.put(uid, set);
  1430. }
  1431. set.add(pkg.packageName);
  1432. if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
  1433. // Schedule a backup for it on general principles
  1434. if (DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName);
  1435. dataChangedImpl(pkg.packageName);
  1436. }
  1437. }
  1438. }
  1439. // Remove the given packages' entries from our known active set.
  1440. void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
  1441. if (packageNames == null) {
  1442. Slog.w(TAG, "removePackageParticipants with null list");
  1443. return;
  1444. }
  1445. if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
  1446. + " #" + packageNames.length);
  1447. for (String pkg : packageNames) {
  1448. // Known previous UID, so we know which package set to check
  1449. HashSet<String> set = mBackupParticipants.get(oldUid);
  1450. if (set != null && set.contains(pkg)) {
  1451. removePackageFromSetLocked(set, pkg);
  1452. if (set.isEmpty()) {
  1453. if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set");
  1454. mBackupParticipants.remove(oldUid);
  1455. }
  1456. }
  1457. }
  1458. }
  1459. private void removePackageFromSetLocked(final HashSet<String> set,
  1460. final String packageName) {
  1461. if (set.contains(packageName)) {
  1462. // Found it. Remove this one package from the bookkeeping, and
  1463. // if it's the last participating app under this uid we drop the
  1464. // (now-empty) set as well.
  1465. // Note that we deliberately leave it 'known' in the "ever backed up"
  1466. // bookkeeping so that its current-dataset data will be retrieved
  1467. // if the app is subsequently reinstalled
  1468. if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName);
  1469. set.remove(packageName);
  1470. mPendingBackups.remove(packageName);
  1471. }
  1472. }
  1473. // Returns the set of all applications that define an android:backupAgent attribute
  1474. List<PackageInfo> allAgentPackages() {
  1475. // !!! TODO: cache this and regenerate only when necessary
  1476. int flags = PackageManager.GET_SIGNATURES;
  1477. List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
  1478. int N = packages.size();
  1479. for (int a = N-1; a >= 0; a--) {
  1480. PackageInfo pkg = packages.get(a);
  1481. try {
  1482. ApplicationInfo app = pkg.applicationInfo;
  1483. if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
  1484. || app.backupAgentName == null) {
  1485. packages.remove(a);
  1486. }
  1487. else {
  1488. // we will need the shared library path, so look that up and store it here
  1489. app = mPackageManager.getApplicationInfo(pkg.packageName,
  1490. PackageManager.GET_SHARED_LIBRARY_FILES);
  1491. pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
  1492. }
  1493. } catch (NameNotFoundException e) {
  1494. packages.remove(a);
  1495. }
  1496. }
  1497. return packages;
  1498. }
  1499. // Called from the backup task: record that the given app has been successfully
  1500. // backed up at least once
  1501. void logBackupComplete(String packageName) {
  1502. if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
  1503. synchronized (mEverStoredApps) {
  1504. if (!mEverStoredApps.add(packageName)) return;
  1505. RandomAccessFile out = null;
  1506. try {
  1507. out = new RandomAccessFile(mEverStored, "rws");
  1508. out.seek(out.length());
  1509. out.writeUTF(packageName);
  1510. } catch (IOException e) {
  1511. Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
  1512. } finally {
  1513. try { if (out != null) out.close(); } catch (IOException e) {}
  1514. }
  1515. }
  1516. }
  1517. // Remove our awareness of having ever backed up the given package
  1518. void removeEverBackedUp(String packageName) {
  1519. if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName);
  1520. if (MORE_DEBUG) Slog.v(TAG, "New set:");
  1521. synchronized (mEverStoredApps) {
  1522. // Rewrite the file and rename to overwrite. If we reboot in the middle,
  1523. // we'll recognize on initialization time that the package no longer
  1524. // exists and fix it up then.
  1525. File tempKnownFile = new File(mBaseStateDir, "processed.new");
  1526. RandomAccessFile known = null;
  1527. try {
  1528. known = new RandomAccessFile(tempKnownFile, "rws");
  1529. mEverStoredApps.remove(packageName);
  1530. for (String s : mEverStoredApps) {
  1531. known.writeUTF(s);
  1532. if (MORE_DEBUG) Slog.v(TAG, " " + s);
  1533. }
  1534. known.close();
  1535. known = null;
  1536. if (!tempKnownFile.renameTo(mEverStored)) {
  1537. throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
  1538. }
  1539. } catch (IOException e) {
  1540. // Bad: we couldn't create the new copy. For safety's sake we
  1541. // abandon the whole process and remove all what's-backed-up
  1542. // state entirely, meaning we'll force a backup pass for every
  1543. // participant on the next boot or [re]install.
  1544. Slog.w(TAG, "Error rewriting " + mEverStored, e);
  1545. mEverStoredApps.clear();
  1546. tempKnownFile.delete();
  1547. mEverStored.delete();
  1548. } finally {
  1549. try { if (known != null) known.close(); } catch (IOException e) {}
  1550. }
  1551. }
  1552. }
  1553. // Persistently record the current and ancestral backup tokens as well
  1554. // as the set of packages with data [supposedly] available in the
  1555. // ancestral dataset.
  1556. void writeRestoreTokens() {
  1557. try {
  1558. RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
  1559. // First, the version number of this record, for futureproofing
  1560. af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
  1561. // Write the ancestral and current tokens
  1562. af.writeLong(mAncestralToken);
  1563. af.writeLong(mCurrentToken);
  1564. // Now write the set of ancestral packages
  1565. if (mAncestralPackages == null) {
  1566. af.writeInt(-1);
  1567. } else {
  1568. af.writeInt(mAncestralPackages.size());
  1569. if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size());
  1570. for (String pkgName : mAncestralPackages) {
  1571. af.writeUTF(pkgName);
  1572. if (MORE_DEBUG) Slog.v(TAG, " " + pkgName);
  1573. }
  1574. }
  1575. af.close();
  1576. } catch (IOException e) {
  1577. Slog.w(TAG, "Unable to write token file:", e);
  1578. }
  1579. }
  1580. // Return the given transport
  1581. private IBackupTransport getTransport(String transportName) {
  1582. synchronized (mTransports) {
  1583. IBackupTransport transport = mTransports.get(transportName);
  1584. if (transport == null) {
  1585. Slog.w(TAG, "Requested unavailable transport: " + transportName);
  1586. }
  1587. return transport;
  1588. }
  1589. }
  1590. // fire off a backup agent, blocking until it attaches or times out
  1591. IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
  1592. IBackupAgent agent = null;
  1593. synchronized(mAgentConnectLock) {
  1594. mConnecting = true;
  1595. mConnectedAgent = null;
  1596. try {
  1597. if (mActivityManager.bindBackupAgent(app, mode)) {
  1598. Slog.d(TAG, "awaiting agent for " + app);
  1599. // success; wait for the agent to arrive
  1600. // only wait 10 seconds for the bind to happen
  1601. long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
  1602. while (mConnecting && mConnectedAgent == null
  1603. && (System.currentTimeMillis() < timeoutMark)) {
  1604. try {
  1605. mAgentConnectLock.wait(5000);
  1606. } catch (InterruptedException e) {
  1607. // just bail
  1608. if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
  1609. mActivityManager.clearPendingBackup();
  1610. return null;
  1611. }
  1612. }
  1613. // if we timed out with no connect, abort and move on
  1614. if (mConnecting == true) {
  1615. Slog.w(TAG, "Timeout waiting for agent " + app);
  1616. mActivityManager.clearPendingBackup();
  1617. return null;
  1618. }
  1619. if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
  1620. agent = mConnectedAgent;
  1621. }
  1622. } catch (RemoteException e) {
  1623. // can't happen - ActivityManager is local
  1624. }
  1625. }
  1626. return agent;
  1627. }
  1628. // clear an application's data, blocking until the operation completes or times out
  1629. void clearApplicationDataSynchronous(String packageName) {
  1630. // Don't wipe packages marked allowClearUserData=false
  1631. try {
  1632. PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
  1633. if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
  1634. if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
  1635. + packageName);
  1636. return;
  1637. }
  1638. } catch (NameNotFoundException e) {
  1639. Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
  1640. return;
  1641. }
  1642. ClearDataObserver observer = new ClearDataObserver();
  1643. synchronized(mClearDataLock) {
  1644. mClearingData = true;
  1645. try {
  1646. mActivityManager.clearApplicationUserData(packageName, observer, 0);
  1647. } catch (RemoteException e) {
  1648. // can't happen because the activity manager is in this process
  1649. }
  1650. // only wait 10 seconds for the clear data to happen
  1651. long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
  1652. while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
  1653. try {
  1654. mClearDataLock.wait(5000);
  1655. } catch (InterruptedException e) {
  1656. // won't happen, but still.
  1657. mClearingData = false;
  1658. }
  1659. }
  1660. }
  1661. }
  1662. class ClearDataObserver extends IPackageDataObserver.Stub {
  1663. public void onRemoveCompleted(String packageName, boolean succeeded) {
  1664. synchronized(mClearDataLock) {
  1665. mClearingData = false;
  1666. mClearDataLock.notifyAll();
  1667. }
  1668. }
  1669. }
  1670. // Get the restore-set token for the best-available restore set for this package:
  1671. // the active set if possible, else the ancestral one. Returns zero if none available.
  1672. long getAvailableRestoreToken(String packageName) {
  1673. long token = mAncestralToken;
  1674. synchronized (mQueueLock) {
  1675. if (mEverStoredApps.contains(packageName)) {
  1676. token = mCurrentToken;
  1677. }
  1678. }
  1679. return token;
  1680. }
  1681. // -----
  1682. // Interface and methods used by the asynchronous-with-timeout backup/restore operations
  1683. interface BackupRestoreTask {
  1684. // Execute one tick of whatever state machine the task implements
  1685. void execute();
  1686. // An operation that wanted a callback has completed
  1687. void operationComplete();
  1688. // An operation that wanted a callback has timed out
  1689. void handleTimeout();
  1690. }
  1691. void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback) {
  1692. if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
  1693. + " interval=" + interval);
  1694. synchronized (mCurrentOpLock) {
  1695. mCurrentOperations.put(token, new Operation(OP_PENDING, callback));
  1696. Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0, callback);
  1697. mBackupHandler.sendMessageDelayed(msg, interval);
  1698. }
  1699. }
  1700. // synchronous waiter case
  1701. boolean waitUntilOperationComplete(int token) {
  1702. if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
  1703. + Integer.toHexString(token));
  1704. int finalState = OP_PENDING;
  1705. Operation op = null;
  1706. synchronized (mCurrentOpLock) {
  1707. while (true) {
  1708. op = mCurrentOperations.get(token);
  1709. if (op == null) {
  1710. // mysterious disappearance: treat as success with no callback
  1711. break;
  1712. } else {
  1713. if (op.state == OP_PENDING) {
  1714. try {
  1715. mCurrentOpLock.wait();
  1716. } catch (InterruptedException e) {}
  1717. // When the wait is notified we loop around and recheck the current state
  1718. } else {
  1719. // No longer pending; we're done
  1720. finalState = op.state;
  1721. break;
  1722. }
  1723. }
  1724. }
  1725. }
  1726. mBackupHandler.removeMessages(MSG_TIMEOUT);
  1727. if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
  1728. + " complete: finalState=" + finalState);
  1729. return finalState == OP_ACKNOWLEDGED;
  1730. }
  1731. void handleTimeout(int token, Object obj) {
  1732. // Notify any synchronous waiters
  1733. Operation op = null;
  1734. synchronized (mCurrentOpLock) {
  1735. op = mCurrentOperations.get(token);
  1736. if (MORE_DEBUG) {
  1737. if (op == null) Slog.w(TAG, "Timeout of token " + Integer.toHexString(token)
  1738. + " but no op found");
  1739. }
  1740. int state = (op != null) ? op.state : OP_TIMEOUT;
  1741. if (state == OP_PENDING) {
  1742. if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + Integer.toHexString(token));
  1743. op.state = OP_TIMEOUT;
  1744. mCurrentOperations.put(token, op);
  1745. }
  1746. mCurrentOpLock.notifyAll();
  1747. }
  1748. // If there's a TimeoutHandler for this event, call it
  1749. if (op != null && op.callback != null) {
  1750. op.callback.handleTimeout();
  1751. }
  1752. }
  1753. // ----- Back up a set of applications via a worker thread -----
  1754. enum BackupState {
  1755. INITIAL,
  1756. RUNNING_QUEUE,
  1757. FINAL
  1758. }
  1759. class PerformBackupTask implements BackupRestoreTask {
  1760. private static final String TAG = "PerformBackupTask";
  1761. IBackupTransport mTransport;
  1762. ArrayList<BackupRequest> mQueue;
  1763. ArrayList<BackupRequest> mOriginalQueue;
  1764. File mStateDir;
  1765. File mJournal;
  1766. BackupState mCurrentState;
  1767. // carried information about the current in-flight operation
  1768. PackageInfo mCurrentPackage;
  1769. File mSavedStateName;
  1770. File mBackupDataName;
  1771. File mNewStateName;
  1772. ParcelFileDescriptor mSavedState;
  1773. ParcelFileDescriptor mBackupData;
  1774. ParcelFileDescriptor mNewState;
  1775. int mStatus;
  1776. boolean mFinished;
  1777. public PerformBackupTask(IBackupTransport transport, String dirName,
  1778. ArrayList<BackupRequest> queue, File journal) {
  1779. mTransport = transport;
  1780. mOriginalQueue = queue;
  1781. mJournal = journal;
  1782. mStateDir = new File(mBaseStateDir, dirName);
  1783. mCurrentState = BackupState.INITIAL;
  1784. mFinished = false;
  1785. addBackupTrace("STATE => INITIAL");
  1786. }
  1787. // Main entry point: perform one chunk of work, updating the state as appropriate
  1788. // and reposting the next chunk to the primary backup handler thread.
  1789. @Override
  1790. public void execute() {
  1791. switch (mCurrentState) {
  1792. case INITIAL:
  1793. beginBackup();
  1794. break;
  1795. case RUNNING_QUEUE:
  1796. invokeNextAgent();
  1797. break;
  1798. case FINAL:
  1799. if (!mFinished) finalizeBackup();
  1800. else {
  1801. Slog.e(TAG, "Duplicate finish");
  1802. }
  1803. mFinished = true;
  1804. break;
  1805. }
  1806. }
  1807. // We're starting a backup pass. Initialize the transport and send
  1808. // the PM metadata blob if we haven't already.
  1809. void beginBackup() {
  1810. if (DEBUG_BACKUP_TRACE) {
  1811. clearBackupTrace();
  1812. StringBuilder b = new StringBuilder(256);
  1813. b.append("beginBackup: [");
  1814. for (BackupRequest req : mOriginalQueue) {
  1815. b.append(' ');
  1816. b.append(req.packageName);
  1817. }
  1818. b.append(" ]");
  1819. addBackupTrace(b.toString());
  1820. }
  1821. mStatus = BackupConstants.TRANSPORT_OK;
  1822. // Sanity check: if the queue is empty we have no work to do.
  1823. if (mOriginalQueue.isEmpty()) {
  1824. Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
  1825. addBackupTrace("queue empty at begin");
  1826. executeNextState(BackupState.FINAL);
  1827. return;
  1828. }
  1829. // We need to retain the original queue contents in case of transport
  1830. // failure, but we want a working copy that we can manipulate along
  1831. // the way.
  1832. mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
  1833. if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
  1834. File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
  1835. try {
  1836. final String transportName = mTransport.transportDirName();
  1837. EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
  1838. // If we haven't stored package manager metadata yet, we must init the transport.
  1839. if (mStatus == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
  1840. Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
  1841. addBackupTrace("initializing transport " + transportName);
  1842. resetBackupState(mStateDir); // Just to make sure.
  1843. mStatus = mTransport.initializeDevice();
  1844. addBackupTrace("transport.initializeDevice() == " + mStatus);
  1845. if (mStatus == BackupConstants.TRANSPORT_OK) {
  1846. EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
  1847. } else {
  1848. EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
  1849. Slog.e(TAG, "Transport error in initializeDevice()");
  1850. }
  1851. }
  1852. // The package manager doesn't have a proper <application> etc, but since
  1853. // it's running here in the system process we can just set up its agent
  1854. // directly and use a synthetic BackupRequest. We always run this pass
  1855. // because it's cheap and this way we guarantee that we don't get out of
  1856. // step even if we're selecting among various transports at run time.
  1857. if (mStatus == BackupConstants.TRANSPORT_OK) {
  1858. PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
  1859. mPackageManager, allAgentPackages());
  1860. mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
  1861. IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
  1862. addBackupTrace("PMBA invoke: " + mStatus);
  1863. }
  1864. if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
  1865. // The backend reports that our dataset has been wiped. Note this in
  1866. // the event log; the no-success code below will reset the backup
  1867. // state as well.
  1868. EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
  1869. }
  1870. } catch (Exception e) {
  1871. Slog.e(TAG, "Error in backup thread", e);
  1872. addBackupTrace("Exception in backup thread: " + e);
  1873. mStatus = BackupConstants.TRANSPORT_ERROR;
  1874. } finally {
  1875. // If we've succeeded so far, invokeAgentForBackup() will have run the PM
  1876. // metadata and its completion/timeout callback will continue the state
  1877. // machine chain. If it failed that won't happen; we handle that now.
  1878. addBackupTrace("exiting prelim: " + mStatus);
  1879. if (mStatus != BackupConstants.TRANSPORT_OK) {
  1880. // if things went wrong at this point, we need to
  1881. // restage everything and try again later.
  1882. resetBackupState(mStateDir); // Just to make sure.
  1883. executeNextState(BackupState.FINAL);
  1884. }
  1885. }
  1886. }
  1887. // Transport has been initialized and the PM metadata submitted successfully
  1888. // if that was warranted. Now we process the single next thing in the queue.
  1889. void invokeNextAgent() {
  1890. mStatus = BackupConstants.TRANSPORT_OK;
  1891. addBackupTrace("invoke q=" + mQueue.size());
  1892. // Sanity check that we have work to do. If not, skip to the end where
  1893. // we reestablish the wakelock invariants etc.
  1894. if (mQueue.isEmpty()) {
  1895. if (DEBUG) Slog.i(TAG, "queue now empty");
  1896. executeNextState(BackupState.FINAL);
  1897. return;
  1898. }
  1899. // pop the entry we're going to process on this step
  1900. BackupRequest request = mQueue.get(0);
  1901. mQueue.remove(0);
  1902. Slog.d(TAG, "starting agent for backup of " + request);
  1903. addBackupTrace("launch agent for " + request.packageName);
  1904. // Verify that the requested app exists; it might be something that
  1905. // requested a backup but was then uninstalled. The request was
  1906. // journalled and rather than tamper with the journal it's safer
  1907. // to sanity-check here. This also gives us the classname of the
  1908. // package's backup agent.
  1909. try {
  1910. mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
  1911. PackageManager.GET_SIGNATURES);
  1912. if (mCurrentPackage.applicationInfo.backupAgentName == null) {
  1913. // The manifest has changed but we had a stale backup request pending.
  1914. // This won't happen again because the app won't be requesting further
  1915. // backups.
  1916. Slog.i(TAG, "Package " + request.packageName
  1917. + " no longer supports backup; skipping");
  1918. addBackupTrace("skipping - no agent, completion is noop");
  1919. executeNextState(BackupState.RUNNING_QUEUE);
  1920. return;
  1921. }
  1922. if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
  1923. // The app has been force-stopped or cleared or just installed,
  1924. // and not yet launched out of that state, so just as it won't
  1925. // receive broadcasts, we won't run it for backup.
  1926. addBackupTrace("skipping - stopped");
  1927. executeNextState(BackupState.RUNNING_QUEUE);
  1928. return;
  1929. }
  1930. IBackupAgent agent = null;
  1931. try {
  1932. mWakelock.setWorkSource(new WorkSource(mCurrentPackage.applicationInfo.uid));
  1933. agent = bindToAgentSynchronous(mCurrentPackage.applicationInfo,
  1934. IApplicationThread.BACKUP_MODE_INCREMENTAL);
  1935. addBackupTrace("agent bound; a? = " + (agent != null));
  1936. if (agent != null) {
  1937. mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
  1938. // at this point we'll either get a completion callback from the
  1939. // agent, or a timeout message on the main handler. either way, we're
  1940. // done here as long as we're successful so far.
  1941. } else {
  1942. // Timeout waiting for the agent
  1943. mStatus = BackupConstants.AGENT_ERROR;
  1944. }
  1945. } catch (SecurityException ex) {
  1946. // Try for the next one.
  1947. Slog.d(TAG, "error in bind/backup", ex);
  1948. mStatus = BackupConstants.AGENT_ERROR;
  1949. addBackupTrace("agent SE");
  1950. }
  1951. } catch (NameNotFoundException e) {
  1952. Slog.d(TAG, "Package does not exist; skipping");
  1953. addBackupTrace("no such package");
  1954. mStatus = BackupConstants.AGENT_UNKNOWN;
  1955. } finally {
  1956. mWakelock.setWorkSource(null);
  1957. // If there was an agent error, no timeout/completion handling will occur.
  1958. // That means we need to direct to the next state ourselves.
  1959. if (mStatus != BackupConstants.TRANSPORT_OK) {
  1960. BackupState nextState = BackupState.RUNNING_QUEUE;
  1961. // An agent-level failure means we reenqueue this one agent for
  1962. // a later retry, but otherwise proceed normally.
  1963. if (mStatus == BackupConstants.AGENT_ERROR) {
  1964. if (MORE_DEBUG) Slog.i(TAG, "Agent failure for " + request.packageName
  1965. + " - restaging");
  1966. dataChangedImpl(request.packageName);
  1967. mStatus = BackupConstants.TRANSPORT_OK;
  1968. if (mQueue.isEmpty()) nextState = BackupState.FINAL;
  1969. } else if (mStatus == BackupConstants.AGENT_UNKNOWN) {
  1970. // Failed lookup of the app, so we couldn't bring up an agent, but
  1971. // we're otherwise fine. Just drop it and go on to the next as usual.
  1972. mStatus = BackupConstants.TRANSPORT_OK;
  1973. } else {
  1974. // Transport-level failure means we reenqueue everything
  1975. revertAndEndBackup();
  1976. nextState = BackupState.FINAL;
  1977. }
  1978. executeNextState(nextState);
  1979. } else {
  1980. addBackupTrace("expecting completion/timeout callback");
  1981. }
  1982. }
  1983. }
  1984. void finalizeBackup() {
  1985. addBackupTrace("finishing");
  1986. // Either backup was successful, in which case we of course do not need
  1987. // this pass's journal any more; or it failed, in which case we just
  1988. // re-enqueued all of these packages in the current active journal.
  1989. // Either way, we no longer need this pass's journal.
  1990. if (mJournal != null && !mJournal.delete()) {
  1991. Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
  1992. }
  1993. // If everything actually went through and this is the first time we've
  1994. // done a backup, we can now record what the current backup dataset token
  1995. // is.
  1996. if ((mCurrentToken == 0) && (mStatus == BackupConstants.TRANSPORT_OK)) {
  1997. addBackupTrace("success; recording token");
  1998. try {
  1999. mCurrentToken = mTransport.getCurrentRestoreSet();
  2000. writeRestoreTokens();
  2001. } catch (RemoteException e) {
  2002. // nothing for it at this point, unfortunately, but this will be
  2003. // recorded the next time we fully succeed.
  2004. addBackupTrace("transport threw returning token");
  2005. }
  2006. }
  2007. // Set up the next backup pass - at this point we can set mBackupRunning
  2008. // to false to allow another pass to fire, because we're done with the
  2009. // state machine sequence and the wakelock is refcounted.
  2010. synchronized (mQueueLock) {
  2011. mBackupRunning = false;
  2012. if (mStatus == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
  2013. // Make sure we back up everything and perform the one-time init
  2014. clearMetadata();
  2015. if (DEBUG) Slog.d(TAG, "Server requires init; rerunning");
  2016. addBackupTrace("init required; rerunning");
  2017. backupNow();
  2018. }
  2019. }
  2020. // Only once we're entirely finished do we release the wakelock
  2021. clearBackupTrace();
  2022. Slog.i(TAG, "Backup pass finished.");
  2023. mWakelock.release();
  2024. }
  2025. // Remove the PM metadata state. This will generate an init on the next pass.
  2026. void clearMetadata() {
  2027. final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
  2028. if (pmState.exists()) pmState.delete();
  2029. }
  2030. // Invoke an agent's doBackup() and start a timeout message spinning on the main
  2031. // handler in case it doesn't get back to us.
  2032. int invokeAgentForBackup(String packageName, IBackupAgent agent,
  2033. IBackupTransport transport) {
  2034. if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
  2035. addBackupTrace("invoking " + packageName);
  2036. mSavedStateName = new File(mStateDir, packageName);
  2037. mBackupDataName = new File(mDataDir, packageName + ".data");
  2038. mNewStateName = new File(mStateDir, packageName + ".new");
  2039. mSavedState = null;
  2040. mBackupData = null;
  2041. mNewState = null;
  2042. final int token = generateToken();
  2043. try {
  2044. // Look up the package info & signatures. This is first so that if it
  2045. // throws an exception, there's no file setup yet that would need to
  2046. // be unraveled.
  2047. if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
  2048. // The metadata 'package' is synthetic; construct one and make
  2049. // sure our global state is pointed at it
  2050. mCurrentPackage = new PackageInfo();
  2051. mCurrentPackage.packageName = packageName;
  2052. }
  2053. // In a full backup, we pass a null ParcelFileDescriptor as
  2054. // the saved-state "file". This is by definition an incremental,
  2055. // so we build a saved state file to pass.
  2056. mSavedState = ParcelFileDescriptor.open(mSavedStateName,
  2057. ParcelFileDescriptor.MODE_READ_ONLY |
  2058. ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
  2059. mBackupData = ParcelFileDescriptor.open(mBackupDataName,
  2060. ParcelFileDescriptor.MODE_READ_WRITE |
  2061. ParcelFileDescriptor.MODE_CREATE |
  2062. ParcelFileDescriptor.MODE_TRUNCATE);
  2063. if (!SELinux.restorecon(mBackupDataName)) {
  2064. Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName);
  2065. }
  2066. mNewState = ParcelFileDescriptor.open(mNewStateName,
  2067. ParcelFileDescriptor.MODE_READ_WRITE |
  2068. ParcelFileDescriptor.MODE_CREATE |
  2069. ParcelFileDescriptor.MODE_TRUNCATE);
  2070. // Initiate the target's backup pass
  2071. addBackupTrace("setting timeout");
  2072. prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, this);
  2073. addBackupTrace("calling agent doBackup()");
  2074. agent.doBackup(mSavedState, mBackupData, mNewState, token, mBackupManagerBinder);
  2075. } catch (Exception e) {
  2076. Slog.e(TAG, "Error invoking for backup on " + packageName);
  2077. addBackupTrace("exception: " + e);
  2078. EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName,
  2079. e.toString());
  2080. agentErrorCleanup();
  2081. return BackupConstants.AGENT_ERROR;
  2082. }
  2083. // At this point the agent is off and running. The next thing to happen will
  2084. // either be a callback from the agent, at which point we'll process its data
  2085. // for transport, or a timeout. Either way the next phase will happen in
  2086. // response to the TimeoutHandler interface callbacks.
  2087. addBackupTrace("invoke success");
  2088. return BackupConstants.TRANSPORT_OK;
  2089. }
  2090. @Override
  2091. public void operationComplete() {
  2092. // Okay, the agent successfully reported back to us. Spin the data off to the
  2093. // transport and proceed with the next stage.
  2094. if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
  2095. + mCurrentPackage.packageName);
  2096. mBackupHandler.removeMessages(MSG_TIMEOUT);
  2097. clearAgentState();
  2098. addBackupTrace("operation complete");
  2099. ParcelFileDescriptor backupData = null;
  2100. mStatus = BackupConstants.TRANSPORT_OK;
  2101. try {
  2102. int size = (int) mBackupDataName.length();
  2103. if (size > 0) {
  2104. if (mStatus == BackupConstants.TRANSPORT_OK) {
  2105. backupData = ParcelFileDescriptor.open(mBackupDataName,
  2106. ParcelFileDescriptor.MODE_READ_ONLY);
  2107. addBackupTrace("sending data to transport");
  2108. mStatus = mTransport.performBackup(mCurrentPackage, backupData);
  2109. }
  2110. // TODO - We call finishBackup() for each application backed up, because
  2111. // we need to know now whether it succeeded or failed. Instead, we should
  2112. // hold off on finishBackup() until the end, which implies holding off on
  2113. // renaming *all* the output state files (see below) until that happens.
  2114. addBackupTrace("data delivered: " + mStatus);
  2115. if (mStatus == BackupConstants.TRANSPORT_OK) {
  2116. addBackupTrace("finishing op on transport");
  2117. mStatus = mTransport.finishBackup();
  2118. addBackupTrace("finished: " + mStatus);
  2119. }
  2120. } else {
  2121. if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
  2122. addBackupTrace("no data to send");
  2123. }
  2124. // After successful transport, delete the now-stale data
  2125. // and juggle the files so that next time we supply the agent
  2126. // with the new state file it just created.
  2127. if (mStatus == BackupConstants.TRANSPORT_OK) {
  2128. mBackupDataName.delete();
  2129. mNewStateName.renameTo(mSavedStateName);
  2130. EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE,
  2131. mCurrentPackage.packageName, size);
  2132. logBackupComplete(mCurrentPackage.packageName);
  2133. } else {
  2134. EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE,
  2135. mCurrentPackage.packageName);
  2136. }
  2137. } catch (Exception e) {
  2138. Slog.e(TAG, "Transport error backing up " + mCurrentPackage.packageName, e);
  2139. EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE,
  2140. mCurrentPackage.packageName);
  2141. mStatus = BackupConstants.TRANSPORT_ERROR;
  2142. } finally {
  2143. try { if (backupData != null) backupData.close(); } catch (IOException e) {}
  2144. }
  2145. // If we encountered an error here it's a transport-level failure. That
  2146. // means we need to halt everything and reschedule everything for next time.
  2147. final BackupState nextState;
  2148. if (mStatus != BackupConstants.TRANSPORT_OK) {
  2149. revertAndEndBackup();
  2150. nextState = BackupState.FINAL;
  2151. } else {
  2152. // Success! Proceed with the next app if any, otherwise we're done.
  2153. nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
  2154. }
  2155. executeNextState(nextState);
  2156. }
  2157. @Override
  2158. public void handleTimeout() {
  2159. // Whoops, the current agent timed out running doBackup(). Tidy up and restage
  2160. // it for the next time we run a backup pass.
  2161. // !!! TODO: keep track of failure counts per agent, and blacklist those which
  2162. // fail repeatedly (i.e. have proved themselves to be buggy).
  2163. Slog.e(TAG, "Timeout backing up " + mCurrentPackage.packageName);
  2164. EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName,
  2165. "timeout");
  2166. addBackupTrace("timeout of " + mCurrentPackage.packageName);
  2167. agentErrorCleanup();
  2168. dataChangedImpl(mCurrentPackage.packageName);
  2169. }
  2170. void revertAndEndBackup() {
  2171. if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
  2172. addBackupTrace("transport error; reverting");
  2173. for (BackupRequest request : mOriginalQueue) {
  2174. dataChangedImpl(request.packageName);
  2175. }
  2176. // We also want to reset the backup schedule based on whatever
  2177. // the transport suggests by way of retry/backoff time.
  2178. restartBackupAlarm();
  2179. }
  2180. void agentErrorCleanup() {
  2181. mBackupDataName.delete();
  2182. mNewStateName.delete();
  2183. clearAgentState();
  2184. executeNextState(mQueue.isEmpty() ? BackupState.FINAL : BackupState.RUNNING_QUEUE);
  2185. }
  2186. // Cleanup common to both success and failure cases
  2187. void clearAgentState() {
  2188. try { if (mSavedState != null) mSavedState.close(); } catch (IOException e) {}
  2189. try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
  2190. try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
  2191. mSavedState = mBackupData = mNewState = null;
  2192. synchronized (mCurrentOpLock) {
  2193. mCurrentOperations.clear();
  2194. }
  2195. // If this was a pseudopackage there's no associated Activity Manager state
  2196. if (mCurrentPackage.applicationInfo != null) {
  2197. addBackupTrace("unbinding " + mCurrentPackage.packageName);
  2198. try { // unbind even on timeout, just in case
  2199. mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
  2200. } catch (RemoteException e) { /* can't happen; activity manager is local */ }
  2201. }
  2202. }
  2203. void restartBackupAlarm() {
  2204. addBackupTrace("setting backup trigger");
  2205. synchronized (mQueueLock) {
  2206. try {
  2207. startBackupAlarmsLocked(mTransport.requestBackupTime());
  2208. } catch (RemoteException e) { /* cannot happen */ }
  2209. }
  2210. }
  2211. void executeNextState(BackupState nextState) {
  2212. if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
  2213. + this + " nextState=" + nextState);
  2214. addBackupTrace("executeNextState => " + nextState);
  2215. mCurrentState = nextState;
  2216. Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
  2217. mBackupHandler.sendMessage(msg);
  2218. }
  2219. }
  2220. // ----- Full backup/restore to a file/socket -----
  2221. abstract class ObbServiceClient {
  2222. public IObbBackupService mObbService;
  2223. public void setObbBinder(IObbBackupService binder) {
  2224. mObbService = binder;
  2225. }
  2226. }
  2227. class FullBackupObbConnection implements ServiceConnection {
  2228. volatile IObbBackupService mService;
  2229. FullBackupObbConnection() {
  2230. mService = null;
  2231. }
  2232. public void establish() {
  2233. if (DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
  2234. Intent obbIntent = new Intent().setComponent(new ComponentName(
  2235. "com.android.sharedstoragebackup",
  2236. "com.android.sharedstoragebackup.ObbBackupService"));
  2237. BackupManagerService.this.mContext.bindService(
  2238. obbIntent, this, Context.BIND_AUTO_CREATE);
  2239. }
  2240. public void tearDown() {
  2241. BackupManagerService.this.mContext.unbindService(this);
  2242. }
  2243. public boolean backupObbs(PackageInfo pkg, OutputStream out) {
  2244. boolean success = false;
  2245. waitForConnection();
  2246. ParcelFileDescriptor[] pipes = null;
  2247. try {
  2248. pipes = ParcelFileDescriptor.createPipe();
  2249. int token = generateToken();
  2250. prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
  2251. mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
  2252. routeSocketDataToOutput(pipes[0], out);
  2253. success = waitUntilOperationComplete(token);
  2254. } catch (Exception e) {
  2255. Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
  2256. } finally {
  2257. try {
  2258. out.flush();
  2259. if (pipes != null) {
  2260. if (pipes[0] != null) pipes[0].close();
  2261. if (pipes[1] != null) pipes[1].close();
  2262. }
  2263. } catch (IOException e) {
  2264. Slog.w(TAG, "I/O error closing down OBB backup", e);
  2265. }
  2266. }
  2267. return success;
  2268. }
  2269. public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
  2270. long fileSize, int type, String path, long mode, long mtime,
  2271. int token, IBackupManager callbackBinder) {
  2272. waitForConnection();
  2273. try {
  2274. mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
  2275. token, callbackBinder);
  2276. } catch (Exception e) {
  2277. Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
  2278. }
  2279. }
  2280. private void waitForConnection() {
  2281. synchronized (this) {
  2282. while (mService == null) {
  2283. if (DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
  2284. try {
  2285. this.wait();
  2286. } catch (InterruptedException e) { /* never interrupted */ }
  2287. }
  2288. if (DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
  2289. }
  2290. }
  2291. @Override
  2292. public void onServiceConnected(ComponentName name, IBinder service) {
  2293. synchronized (this) {
  2294. mService = IObbBackupService.Stub.asInterface(service);
  2295. if (DEBUG) Slog.i(TAG, "OBB service connection " + mService
  2296. + " connected on " + this);
  2297. this.notifyAll();
  2298. }
  2299. }
  2300. @Override
  2301. public void onServiceDisconnected(ComponentName name) {
  2302. synchronized (this) {
  2303. mService = null;
  2304. if (DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
  2305. this.notifyAll();
  2306. }
  2307. }
  2308. }
  2309. private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
  2310. throws IOException {
  2311. FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
  2312. DataInputStream in = new DataInputStream(raw);
  2313. byte[] buffer = new byte[32 * 1024];
  2314. int chunkTotal;
  2315. while ((chunkTotal = in.readInt()) > 0) {
  2316. while (chunkTotal > 0) {
  2317. int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
  2318. int nRead = in.read(buffer, 0, toRead);
  2319. out.write(buffer, 0, nRead);
  2320. chunkTotal -= nRead;
  2321. }
  2322. }
  2323. }
  2324. class PerformFullBackupTask extends ObbServiceClient implements Runnable {
  2325. ParcelFileDescriptor mOutputFile;
  2326. DeflaterOutputStream mDeflater;
  2327. IFullBackupRestoreObserver mObserver;
  2328. boolean mIncludeApks;
  2329. boolean mIncludeObbs;
  2330. boolean mIncludeShared;
  2331. boolean mAllApps;
  2332. final boolean mIncludeSystem;
  2333. String[] mPackages;
  2334. String mCurrentPassword;
  2335. String mEncryptPassword;
  2336. AtomicBoolean mLatchObject;
  2337. File mFilesDir;
  2338. File mManifestFile;
  2339. class FullBackupRunner implements Runnable {
  2340. PackageInfo mPackage;
  2341. IBackupAgent mAgent;
  2342. ParcelFileDescriptor mPipe;
  2343. int mToken;
  2344. boolean mSendApk;
  2345. boolean mWriteManifest;
  2346. FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
  2347. int token, boolean sendApk, boolean writeManifest) throws IOException {
  2348. mPackage = pack;
  2349. mAgent = agent;
  2350. mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
  2351. mToken = token;
  2352. mSendApk = sendApk;
  2353. mWriteManifest = writeManifest;
  2354. }
  2355. @Override
  2356. public void run() {
  2357. try {
  2358. BackupDataOutput output = new BackupDataOutput(
  2359. mPipe.getFileDescriptor());
  2360. if (mWriteManifest) {
  2361. if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
  2362. writeAppManifest(mPackage, mManifestFile, mSendApk);
  2363. FullBackup.backupToTar(mPackage.packageName, null, null,
  2364. mFilesDir.getAbsolutePath(),
  2365. mManifestFile.getAbsolutePath(),
  2366. output);
  2367. }
  2368. if (mSendApk) {
  2369. writeApkToBackup(mPackage, output);
  2370. }
  2371. if (DEBUG) Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
  2372. prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL, null);
  2373. mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
  2374. } catch (IOException e) {
  2375. Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
  2376. } catch (RemoteException e) {
  2377. Slog.e(TAG, "Remote agent vanished during full backup of "
  2378. + mPackage.packageName);
  2379. } finally {
  2380. try {
  2381. mPipe.close();
  2382. } catch (IOException e) {}
  2383. }
  2384. }
  2385. }
  2386. PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
  2387. boolean includeApks, boolean includeObbs, boolean includeShared,
  2388. String curPassword, String encryptPassword, boolean doAllApps,
  2389. boolean doSystem, String[] packages, AtomicBoolean latch) {
  2390. mOutputFile = fd;
  2391. mObserver = observer;
  2392. mIncludeApks = includeApks;
  2393. mIncludeObbs = includeObbs;
  2394. mIncludeShared = includeShared;
  2395. mAllApps = doAllApps;
  2396. mIncludeSystem = doSystem;
  2397. mPackages = packages;
  2398. mCurrentPassword = curPassword;
  2399. // when backing up, if there is a current backup password, we require that
  2400. // the user use a nonempty encryption password as well. if one is supplied
  2401. // in the UI we use that, but if the UI was left empty we fall back to the
  2402. // current backup password (which was supplied by the user as well).
  2403. if (encryptPassword == null || "".equals(encryptPassword)) {
  2404. mEncryptPassword = curPassword;
  2405. } else {
  2406. mEncryptPassword = encryptPassword;
  2407. }
  2408. mLatchObject = latch;
  2409. mFilesDir = new File("/data/system");
  2410. mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
  2411. }
  2412. @Override
  2413. public void run() {
  2414. Slog.i(TAG, "--- Performing full-dataset backup ---");
  2415. List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
  2416. FullBackupObbConnection obbConnection = new FullBackupObbConnection();
  2417. obbConnection.establish(); // we'll want this later
  2418. sendStartBackup();
  2419. // doAllApps supersedes the package set if any
  2420. if (mAllApps) {
  2421. packagesToBackup = mPackageManager.getInstalledPackages(
  2422. PackageManager.GET_SIGNATURES);
  2423. // Exclude system apps if we've been asked to do so
  2424. if (mIncludeSystem == false) {
  2425. for (int i = 0; i < packagesToBackup.size(); ) {
  2426. PackageInfo pkg = packagesToBackup.get(i);
  2427. if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
  2428. packagesToBackup.remove(i);
  2429. } else {
  2430. i++;
  2431. }
  2432. }
  2433. }
  2434. }
  2435. // Now process the command line argument packages, if any. Note that explicitly-
  2436. // named system-partition packages will be included even if includeSystem was
  2437. // set to false.
  2438. if (mPackages != null) {
  2439. for (String pkgName : mPackages) {
  2440. try {
  2441. packagesToBackup.add(mPackageManager.getPackageInfo(pkgName,
  2442. PackageManager.GET_SIGNATURES));
  2443. } catch (NameNotFoundException e) {
  2444. Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
  2445. }
  2446. }
  2447. }
  2448. // Cull any packages that have indicated that backups are not permitted, as well
  2449. // as any explicit mention of the 'special' shared-storage agent package (we
  2450. // handle that one at the end).
  2451. for (int i = 0; i < packagesToBackup.size(); ) {
  2452. PackageInfo pkg = packagesToBackup.get(i);
  2453. if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
  2454. || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
  2455. packagesToBackup.remove(i);
  2456. } else {
  2457. i++;
  2458. }
  2459. }
  2460. // Cull any packages that run as system-domain uids but do not define their
  2461. // own backup agents
  2462. for (int i = 0; i < packagesToBackup.size(); ) {
  2463. PackageInfo pkg = packagesToBackup.get(i);
  2464. if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
  2465. && (pkg.applicationInfo.backupAgentName == null)) {
  2466. if (MORE_DEBUG) {
  2467. Slog.i(TAG, "... ignoring non-agent system package " + pkg.packageName);
  2468. }
  2469. packagesToBackup.remove(i);
  2470. } else {
  2471. i++;
  2472. }
  2473. }
  2474. FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
  2475. OutputStream out = null;
  2476. PackageInfo pkg = null;
  2477. try {
  2478. boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
  2479. boolean compressing = COMPRESS_FULL_BACKUPS;
  2480. OutputStream finalOutput = ofstream;
  2481. // Verify that the given password matches the currently-active
  2482. // backup password, if any
  2483. if (!backupPasswordMatches(mCurrentPassword)) {
  2484. if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
  2485. return;
  2486. }
  2487. // Write the global file header. All strings are UTF-8 encoded; lines end
  2488. // with a '\n' byte. Actual backup data begins immediately following the
  2489. // final '\n'.
  2490. //
  2491. // line 1: "ANDROID BACKUP"
  2492. // line 2: backup file format version, currently "2"
  2493. // line 3: compressed? "0" if not compressed, "1" if compressed.
  2494. // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
  2495. //
  2496. // When line 4 is not "none", then additional header data follows:
  2497. //
  2498. // line 5: user password salt [hex]
  2499. // line 6: master key checksum salt [hex]
  2500. // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
  2501. // line 8: IV of the user key [hex]
  2502. // line 9: master key blob [hex]
  2503. // IV of the master key, master key itself, master key checksum hash
  2504. //
  2505. // The master key checksum is the master key plus its checksum salt, run through
  2506. // 10k rounds of PBKDF2. This is used to verify that the user has supplied the
  2507. // correct password for decrypting the archive: the master key decrypted from
  2508. // the archive using the user-supplied password is also run through PBKDF2 in
  2509. // this way, and if the result does not match the checksum as stored in the
  2510. // archive, then we know that the user-supplied password does not match the
  2511. // archive's.
  2512. StringBuilder headerbuf = new StringBuilder(1024);
  2513. headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
  2514. headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
  2515. headerbuf.append(compressing ? "\n1\n" : "\n0\n");
  2516. try {
  2517. // Set up the encryption stage if appropriate, and emit the correct header
  2518. if (encrypting) {
  2519. finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
  2520. } else {
  2521. headerbuf.append("none\n");
  2522. }
  2523. byte[] header = headerbuf.toString().getBytes("UTF-8");
  2524. ofstream.write(header);
  2525. // Set up the compression stage feeding into the encryption stage (if any)
  2526. if (compressing) {
  2527. Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
  2528. finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
  2529. }
  2530. out = finalOutput;
  2531. } catch (Exception e) {
  2532. // Should never happen!
  2533. Slog.e(TAG, "Unable to emit archive header", e);
  2534. return;
  2535. }
  2536. // Shared storage if requested
  2537. if (mIncludeShared) {
  2538. try {
  2539. pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
  2540. packagesToBackup.add(pkg);
  2541. } catch (NameNotFoundException e) {
  2542. Slog.e(TAG, "Unable to find shared-storage backup handler");
  2543. }
  2544. }
  2545. // Now back up the app data via the agent mechanism
  2546. int N = packagesToBackup.size();
  2547. for (int i = 0; i < N; i++) {
  2548. pkg = packagesToBackup.get(i);
  2549. backupOnePackage(pkg, out);
  2550. // after the app's agent runs to handle its private filesystem
  2551. // contents, back up any OBB content it has on its behalf.
  2552. if (mIncludeObbs) {
  2553. boolean obbOkay = obbConnection.backupObbs(pkg, out);
  2554. if (!obbOkay) {
  2555. throw new RuntimeException("Failure writing OBB stack for " + pkg);
  2556. }
  2557. }
  2558. }
  2559. // Done!
  2560. finalizeBackup(out);
  2561. } catch (RemoteException e) {
  2562. Slog.e(TAG, "App died during full backup");
  2563. } catch (Exception e) {
  2564. Slog.e(TAG, "Internal exception during full backup", e);
  2565. } finally {
  2566. tearDown(pkg);
  2567. try {
  2568. if (out != null) out.close();
  2569. mOutputFile.close();
  2570. } catch (IOException e) {
  2571. /* nothing we can do about this */
  2572. }
  2573. synchronized (mCurrentOpLock) {
  2574. mCurrentOperations.clear();
  2575. }
  2576. synchronized (mLatchObject) {
  2577. mLatchObject.set(true);
  2578. mLatchObject.notifyAll();
  2579. }
  2580. sendEndBackup();
  2581. obbConnection.tearDown();
  2582. if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
  2583. mWakelock.release();
  2584. }
  2585. }
  2586. private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
  2587. OutputStream ofstream) throws Exception {
  2588. // User key will be used to encrypt the master key.
  2589. byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
  2590. SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
  2591. PBKDF2_HASH_ROUNDS);
  2592. // the master key is random for each backup
  2593. byte[] masterPw = new byte[256 / 8];
  2594. mRng.nextBytes(masterPw);
  2595. byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
  2596. // primary encryption of the datastream with the random key
  2597. Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
  2598. SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
  2599. c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
  2600. OutputStream finalOutput = new CipherOutputStream(ofstream, c);
  2601. // line 4: name of encryption algorithm
  2602. headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
  2603. headerbuf.append('\n');
  2604. // line 5: user password salt [hex]
  2605. headerbuf.append(byteArrayToHex(newUserSalt));
  2606. headerbuf.append('\n');
  2607. // line 6: master key checksum salt [hex]
  2608. headerbuf.append(byteArrayToHex(checksumSalt));
  2609. headerbuf.append('\n');
  2610. // line 7: number of PBKDF2 rounds used [decimal]
  2611. headerbuf.append(PBKDF2_HASH_ROUNDS);
  2612. headerbuf.append('\n');
  2613. // line 8: IV of the user key [hex]
  2614. Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
  2615. mkC.init(Cipher.ENCRYPT_MODE, userKey);
  2616. byte[] IV = mkC.getIV();
  2617. headerbuf.append(byteArrayToHex(IV));
  2618. headerbuf.append('\n');
  2619. // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format:
  2620. // [byte] IV length = Niv
  2621. // [array of Niv bytes] IV itself
  2622. // [byte] master key length = Nmk
  2623. // [array of Nmk bytes] master key itself
  2624. // [byte] MK checksum hash length = Nck
  2625. // [array of Nck bytes] master key checksum hash
  2626. //
  2627. // The checksum is the (master key + checksum salt), run through the
  2628. // stated number of PBKDF2 rounds
  2629. IV = c.getIV();
  2630. byte[] mk = masterKeySpec.getEncoded();
  2631. byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
  2632. checksumSalt, PBKDF2_HASH_ROUNDS);
  2633. ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
  2634. + checksum.length + 3);
  2635. DataOutputStream mkOut = new DataOutputStream(blob);
  2636. mkOut.writeByte(IV.length);
  2637. mkOut.write(IV);
  2638. mkOut.writeByte(mk.length);
  2639. mkOut.write(mk);
  2640. mkOut.writeByte(checksum.length);
  2641. mkOut.write(checksum);
  2642. mkOut.flush();
  2643. byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
  2644. headerbuf.append(byteArrayToHex(encryptedMk));
  2645. headerbuf.append('\n');
  2646. return finalOutput;
  2647. }
  2648. private void backupOnePackage(PackageInfo pkg, OutputStream out)
  2649. throws RemoteException {
  2650. Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
  2651. IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
  2652. IApplicationThread.BACKUP_MODE_FULL);
  2653. if (agent != null) {
  2654. ParcelFileDescriptor[] pipes = null;
  2655. try {
  2656. pipes = ParcelFileDescriptor.createPipe();
  2657. ApplicationInfo app = pkg.applicationInfo;
  2658. final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
  2659. final boolean sendApk = mIncludeApks
  2660. && !isSharedStorage
  2661. && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
  2662. && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
  2663. (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
  2664. sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
  2665. final int token = generateToken();
  2666. FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
  2667. token, sendApk, !isSharedStorage);
  2668. pipes[1].close(); // the runner has dup'd it
  2669. pipes[1] = null;
  2670. Thread t = new Thread(runner);
  2671. t.start();
  2672. // Now pull data from the app and stuff it into the compressor
  2673. try {
  2674. routeSocketDataToOutput(pipes[0], out);
  2675. } catch (IOException e) {
  2676. Slog.i(TAG, "Caught exception reading from agent", e);
  2677. }
  2678. if (!waitUntilOperationComplete(token)) {
  2679. Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
  2680. } else {
  2681. if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
  2682. }
  2683. } catch (IOException e) {
  2684. Slog.e(TAG, "Error backing up " + pkg.packageName, e);
  2685. } finally {
  2686. try {
  2687. // flush after every package
  2688. out.flush();
  2689. if (pipes != null) {
  2690. if (pipes[0] != null) pipes[0].close();
  2691. if (pipes[1] != null) pipes[1].close();
  2692. }
  2693. } catch (IOException e) {
  2694. Slog.w(TAG, "Error bringing down backup stack");
  2695. }
  2696. }
  2697. } else {
  2698. Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
  2699. }
  2700. tearDown(pkg);
  2701. }
  2702. private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
  2703. // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
  2704. final String appSourceDir = pkg.applicationInfo.sourceDir;
  2705. final String apkDir = new File(appSourceDir).getParent();
  2706. FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
  2707. apkDir, appSourceDir, output);
  2708. // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
  2709. // doesn't have access to external storage.
  2710. // Save associated .obb content if it exists and we did save the apk
  2711. // check for .obb and save those too
  2712. final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
  2713. final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
  2714. if (obbDir != null) {
  2715. if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
  2716. File[] obbFiles = obbDir.listFiles();
  2717. if (obbFiles != null) {
  2718. final String obbDirName = obbDir.getAbsolutePath();
  2719. for (File obb : obbFiles) {
  2720. FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
  2721. obbDirName, obb.getAbsolutePath(), output);
  2722. }
  2723. }
  2724. }
  2725. }
  2726. private void finalizeBackup(OutputStream out) {
  2727. try {
  2728. // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
  2729. byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
  2730. out.write(eof);
  2731. } catch (IOException e) {
  2732. Slog.w(TAG, "Error attempting to finalize backup stream");
  2733. }
  2734. }
  2735. private void writeAppManifest(PackageInfo pkg, File manifestFile, boolean withApk)
  2736. throws IOException {
  2737. // Manifest format. All data are strings ending in LF:
  2738. // BACKUP_MANIFEST_VERSION, currently 1
  2739. //
  2740. // Version 1:
  2741. // package name
  2742. // package's versionCode
  2743. // platform versionCode
  2744. // getInstallerPackageName() for this package (maybe empty)
  2745. // boolean: "1" if archive includes .apk; any other string means not
  2746. // number of signatures == N
  2747. // N*: signature byte array in ascii format per Signature.toCharsString()
  2748. StringBuilder builder = new StringBuilder(4096);
  2749. StringBuilderPrinter printer = new StringBuilderPrinter(builder);
  2750. printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
  2751. printer.println(pkg.packageName);
  2752. printer.println(Integer.toString(pkg.versionCode));
  2753. printer.println(Integer.toString(Build.VERSION.SDK_INT));
  2754. String installerName = mPackageManager.getInstallerPackageName(pkg.packageName);
  2755. printer.println((installerName != null) ? installerName : "");
  2756. printer.println(withApk ? "1" : "0");
  2757. if (pkg.signatures == null) {
  2758. printer.println("0");
  2759. } else {
  2760. printer.println(Integer.toString(pkg.signatures.length));
  2761. for (Signature sig : pkg.signatures) {
  2762. printer.println(sig.toCharsString());
  2763. }
  2764. }
  2765. FileOutputStream outstream = new FileOutputStream(manifestFile);
  2766. outstream.write(builder.toString().getBytes());
  2767. outstream.close();
  2768. }
  2769. private void tearDown(PackageInfo pkg) {
  2770. if (pkg != null) {
  2771. final ApplicationInfo app = pkg.applicationInfo;
  2772. if (app != null) {
  2773. try {
  2774. // unbind and tidy up even on timeout or failure, just in case
  2775. mActivityManager.unbindBackupAgent(app);
  2776. // The agent was running with a stub Application object, so shut it down.
  2777. if (app.uid != Process.SYSTEM_UID
  2778. && app.uid != Process.PHONE_UID) {
  2779. if (MORE_DEBUG) Slog.d(TAG, "Backup complete, killing host process");
  2780. mActivityManager.killApplicationProcess(app.processName, app.uid);
  2781. } else {
  2782. if (MORE_DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
  2783. }
  2784. } catch (RemoteException e) {
  2785. Slog.d(TAG, "Lost app trying to shut down");
  2786. }
  2787. }
  2788. }
  2789. }
  2790. // wrappers for observer use
  2791. void sendStartBackup() {
  2792. if (mObserver != null) {
  2793. try {
  2794. mObserver.onStartBackup();
  2795. } catch (RemoteException e) {
  2796. Slog.w(TAG, "full backup observer went away: startBackup");
  2797. mObserver = null;
  2798. }
  2799. }
  2800. }
  2801. void sendOnBackupPackage(String name) {
  2802. if (mObserver != null) {
  2803. try {
  2804. // TODO: use a more user-friendly name string
  2805. mObserver.onBackupPackage(name);
  2806. } catch (RemoteException e) {
  2807. Slog.w(TAG, "full backup observer went away: backupPackage");
  2808. mObserver = null;
  2809. }
  2810. }
  2811. }
  2812. void sendEndBackup() {
  2813. if (mObserver != null) {
  2814. try {
  2815. mObserver.onEndBackup();
  2816. } catch (RemoteException e) {
  2817. Slog.w(TAG, "full backup observer went away: endBackup");
  2818. mObserver = null;
  2819. }
  2820. }
  2821. }
  2822. }
  2823. // ----- Full restore from a file/socket -----
  2824. // Description of a file in the restore datastream
  2825. static class FileMetadata {
  2826. String packageName; // name of the owning app
  2827. String installerPackageName; // name of the market-type app that installed the owner
  2828. int type; // e.g. BackupAgent.TYPE_DIRECTORY
  2829. String domain; // e.g. FullBackup.DATABASE_TREE_TOKEN
  2830. String path; // subpath within the semantic domain
  2831. long mode; // e.g. 0666 (actually int)
  2832. long mtime; // last mod time, UTC time_t (actually int)
  2833. long size; // bytes of content
  2834. @Override
  2835. public String toString() {
  2836. StringBuilder sb = new StringBuilder(128);
  2837. sb.append("FileMetadata{");
  2838. sb.append(packageName); sb.append(',');
  2839. sb.append(type); sb.append(',');
  2840. sb.append(domain); sb.append(':'); sb.append(path); sb.append(',');
  2841. sb.append(size);
  2842. sb.append('}');
  2843. return sb.toString();
  2844. }
  2845. }
  2846. enum RestorePolicy {
  2847. IGNORE,
  2848. ACCEPT,
  2849. ACCEPT_IF_APK
  2850. }
  2851. class PerformFullRestoreTask extends ObbServiceClient implements Runnable {
  2852. ParcelFileDescriptor mInputFile;
  2853. String mCurrentPassword;
  2854. String mDecryptPassword;
  2855. IFullBackupRestoreObserver mObserver;
  2856. AtomicBoolean mLatchObject;
  2857. IBackupAgent mAgent;
  2858. String mAgentPackage;
  2859. ApplicationInfo mTargetApp;
  2860. FullBackupObbConnection mObbConnection = null;
  2861. ParcelFileDescriptor[] mPipes = null;
  2862. long mBytes;
  2863. // possible handling states for a given package in the restore dataset
  2864. final HashMap<String, RestorePolicy> mPackagePolicies
  2865. = new HashMap<String, RestorePolicy>();
  2866. // installer package names for each encountered app, derived from the manifests
  2867. final HashMap<String, String> mPackageInstallers = new HashMap<String, String>();
  2868. // Signatures for a given package found in its manifest file
  2869. final HashMap<String, Signature[]> mManifestSignatures
  2870. = new HashMap<String, Signature[]>();
  2871. // Packages we've already wiped data on when restoring their first file
  2872. final HashSet<String> mClearedPackages = new HashSet<String>();
  2873. PerformFullRestoreTask(ParcelFileDescriptor fd, String curPassword, String decryptPassword,
  2874. IFullBackupRestoreObserver observer, AtomicBoolean latch) {
  2875. mInputFile = fd;
  2876. mCurrentPassword = curPassword;
  2877. mDecryptPassword = decryptPassword;
  2878. mObserver = observer;
  2879. mLatchObject = latch;
  2880. mAgent = null;
  2881. mAgentPackage = null;
  2882. mTargetApp = null;
  2883. mObbConnection = new FullBackupObbConnection();
  2884. // Which packages we've already wiped data on. We prepopulate this
  2885. // with a whitelist of packages known to be unclearable.
  2886. mClearedPackages.add("android");
  2887. mClearedPackages.add("com.android.providers.settings");
  2888. }
  2889. class RestoreFileRunnable implements Runnable {
  2890. IBackupAgent mAgent;
  2891. FileMetadata mInfo;
  2892. ParcelFileDescriptor mSocket;
  2893. int mToken;
  2894. RestoreFileRunnable(IBackupAgent agent, FileMetadata info,
  2895. ParcelFileDescriptor socket, int token) throws IOException {
  2896. mAgent = agent;
  2897. mInfo = info;
  2898. mToken = token;
  2899. // This class is used strictly for process-local binder invocations. The
  2900. // semantics of ParcelFileDescriptor differ in this case; in particular, we
  2901. // do not automatically get a 'dup'ed descriptor that we can can continue
  2902. // to use asynchronously from the caller. So, we make sure to dup it ourselves
  2903. // before proceeding to do the restore.
  2904. mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
  2905. }
  2906. @Override
  2907. public void run() {
  2908. try {
  2909. mAgent.doRestoreFile(mSocket, mInfo.size, mInfo.type,
  2910. mInfo.domain, mInfo.path, mInfo.mode, mInfo.mtime,
  2911. mToken, mBackupManagerBinder);
  2912. } catch (RemoteException e) {
  2913. // never happens; this is used strictly for local binder calls
  2914. }
  2915. }
  2916. }
  2917. @Override
  2918. public void run() {
  2919. Slog.i(TAG, "--- Performing full-dataset restore ---");
  2920. mObbConnection.establish();
  2921. sendStartRestore();
  2922. // Are we able to restore shared-storage data?
  2923. if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
  2924. mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
  2925. }
  2926. FileInputStream rawInStream = null;
  2927. DataInputStream rawDataIn = null;
  2928. try {
  2929. if (!backupPasswordMatches(mCurrentPassword)) {
  2930. if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
  2931. return;
  2932. }
  2933. mBytes = 0;
  2934. byte[] buffer = new byte[32 * 1024];
  2935. rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
  2936. rawDataIn = new DataInputStream(rawInStream);
  2937. // First, parse out the unencrypted/uncompressed header
  2938. boolean compressed = false;
  2939. InputStream preCompressStream = rawInStream;
  2940. final InputStream in;
  2941. boolean okay = false;
  2942. final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
  2943. byte[] streamHeader = new byte[headerLen];
  2944. rawDataIn.readFully(streamHeader);
  2945. byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
  2946. if (Arrays.equals(magicBytes, streamHeader)) {
  2947. // okay, header looks good. now parse out the rest of the fields.
  2948. String s = readHeaderLine(rawInStream);
  2949. final int archiveVersion = Integer.parseInt(s);
  2950. if (archiveVersion <= BACKUP_FILE_VERSION) {
  2951. // okay, it's a version we recognize. if it's version 1, we may need
  2952. // to try two different PBKDF2 regimes to compare checksums.
  2953. final boolean pbkdf2Fallback = (archiveVersion == 1);
  2954. s = readHeaderLine(rawInStream);
  2955. compressed = (Integer.parseInt(s) != 0);
  2956. s = readHeaderLine(rawInStream);
  2957. if (s.equals("none")) {
  2958. // no more header to parse; we're good to go
  2959. okay = true;
  2960. } else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
  2961. preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback,
  2962. rawInStream);
  2963. if (preCompressStream != null) {
  2964. okay = true;
  2965. }
  2966. } else Slog.w(TAG, "Archive is encrypted but no password given");
  2967. } else Slog.w(TAG, "Wrong header version: " + s);
  2968. } else Slog.w(TAG, "Didn't read the right header magic");
  2969. if (!okay) {
  2970. Slog.w(TAG, "Invalid restore data; aborting.");
  2971. return;
  2972. }
  2973. // okay, use the right stream layer based on compression
  2974. in = (compressed) ? new InflaterInputStream(preCompressStream) : preCompressStream;
  2975. boolean didRestore;
  2976. do {
  2977. didRestore = restoreOneFile(in, buffer);
  2978. } while (didRestore);
  2979. if (MORE_DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
  2980. } catch (IOException e) {
  2981. Slog.e(TAG, "Unable to read restore input");
  2982. } finally {
  2983. tearDownPipes();
  2984. tearDownAgent(mTargetApp);
  2985. try {
  2986. if (rawDataIn != null) rawDataIn.close();
  2987. if (rawInStream != null) rawInStream.close();
  2988. mInputFile.close();
  2989. } catch (IOException e) {
  2990. Slog.w(TAG, "Close of restore data pipe threw", e);
  2991. /* nothing we can do about this */
  2992. }
  2993. synchronized (mCurrentOpLock) {
  2994. mCurrentOperations.clear();
  2995. }
  2996. synchronized (mLatchObject) {
  2997. mLatchObject.set(true);
  2998. mLatchObject.notifyAll();
  2999. }
  3000. mObbConnection.tearDown();
  3001. sendEndRestore();
  3002. Slog.d(TAG, "Full restore pass complete.");
  3003. mWakelock.release();
  3004. }
  3005. }
  3006. String readHeaderLine(InputStream in) throws IOException {
  3007. int c;
  3008. StringBuilder buffer = new StringBuilder(80);
  3009. while ((c = in.read()) >= 0) {
  3010. if (c == '\n') break; // consume and discard the newlines
  3011. buffer.append((char)c);
  3012. }
  3013. return buffer.toString();
  3014. }
  3015. InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt,
  3016. int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
  3017. boolean doLog) {
  3018. InputStream result = null;
  3019. try {
  3020. Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
  3021. SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt,
  3022. rounds);
  3023. byte[] IV = hexToByteArray(userIvHex);
  3024. IvParameterSpec ivSpec = new IvParameterSpec(IV);
  3025. c.init(Cipher.DECRYPT_MODE,
  3026. new SecretKeySpec(userKey.getEncoded(), "AES"),
  3027. ivSpec);
  3028. byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
  3029. byte[] mkBlob = c.doFinal(mkCipher);
  3030. // first, the master key IV
  3031. int offset = 0;
  3032. int len = mkBlob[offset++];
  3033. IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
  3034. offset += len;
  3035. // then the master key itself
  3036. len = mkBlob[offset++];
  3037. byte[] mk = Arrays.copyOfRange(mkBlob,
  3038. offset, offset + len);
  3039. offset += len;
  3040. // and finally the master key checksum hash
  3041. len = mkBlob[offset++];
  3042. byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
  3043. offset, offset + len);
  3044. // now validate the decrypted master key against the checksum
  3045. byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds);
  3046. if (Arrays.equals(calculatedCk, mkChecksum)) {
  3047. ivSpec = new IvParameterSpec(IV);
  3048. c.init(Cipher.DECRYPT_MODE,
  3049. new SecretKeySpec(mk, "AES"),
  3050. ivSpec);
  3051. // Only if all of the above worked properly will 'result' be assigned
  3052. result = new CipherInputStream(rawInStream, c);
  3053. } else if (doLog) Slog.w(TAG, "Incorrect password");
  3054. } catch (InvalidAlgorithmParameterException e) {
  3055. if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e);
  3056. } catch (BadPaddingException e) {
  3057. // This case frequently occurs when the wrong password is used to decrypt
  3058. // the master key. Use the identical "incorrect password" log text as is
  3059. // used in the checksum failure log in order to avoid providing additional
  3060. // information to an attacker.
  3061. if (doLog) Slog.w(TAG, "Incorrect password");
  3062. } catch (IllegalBlockSizeException e) {
  3063. if (doLog) Slog.w(TAG, "Invalid block size in master key");
  3064. } catch (NoSuchAlgorithmException e) {
  3065. if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!");
  3066. } catch (NoSuchPaddingException e) {
  3067. if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!");
  3068. } catch (InvalidKeyException e) {
  3069. if (doLog) Slog.w(TAG, "Illegal password; aborting");
  3070. }
  3071. return result;
  3072. }
  3073. InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback,
  3074. InputStream rawInStream) {
  3075. InputStream result = null;
  3076. try {
  3077. if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
  3078. String userSaltHex = readHeaderLine(rawInStream); // 5
  3079. byte[] userSalt = hexToByteArray(userSaltHex);
  3080. String ckSaltHex = readHeaderLine(rawInStream); // 6
  3081. byte[] ckSalt = hexToByteArray(ckSaltHex);
  3082. int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
  3083. String userIvHex = readHeaderLine(rawInStream); // 8
  3084. String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
  3085. // decrypt the master key blob
  3086. result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt,
  3087. rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
  3088. if (result == null && pbkdf2Fallback) {
  3089. result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt,
  3090. rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
  3091. }
  3092. } else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
  3093. } catch (NumberFormatException e) {
  3094. Slog.w(TAG, "Can't parse restore data header");
  3095. } catch (IOException e) {
  3096. Slog.w(TAG, "Can't read input header");
  3097. }
  3098. return result;
  3099. }
  3100. boolean restoreOneFile(InputStream instream, byte[] buffer) {
  3101. FileMetadata info;
  3102. try {
  3103. info = readTarHeaders(instream);
  3104. if (info != null) {
  3105. if (MORE_DEBUG) {
  3106. dumpFileMetadata(info);
  3107. }
  3108. final String pkg = info.packageName;
  3109. if (!pkg.equals(mAgentPackage)) {
  3110. // okay, change in package; set up our various
  3111. // bookkeeping if we haven't seen it yet
  3112. if (!mPackagePolicies.containsKey(pkg)) {
  3113. mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
  3114. }
  3115. // Clean up the previous agent relationship if necessary,
  3116. // and let the observer know we're considering a new app.
  3117. if (mAgent != null) {
  3118. if (DEBUG) Slog.d(TAG, "Saw new package; tearing down old one");
  3119. tearDownPipes();
  3120. tearDownAgent(mTargetApp);
  3121. mTargetApp = null;
  3122. mAgentPackage = null;
  3123. }
  3124. }
  3125. if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
  3126. mPackagePolicies.put(pkg, readAppManifest(info, instream));
  3127. mPackageInstallers.put(pkg, info.installerPackageName);
  3128. // We've read only the manifest content itself at this point,
  3129. // so consume the footer before looping around to the next
  3130. // input file
  3131. skipTarPadding(info.size, instream);
  3132. sendOnRestorePackage(pkg);
  3133. } else {
  3134. // Non-manifest, so it's actual file data. Is this a package
  3135. // we're ignoring?
  3136. boolean okay = true;
  3137. RestorePolicy policy = mPackagePolicies.get(pkg);
  3138. switch (policy) {
  3139. case IGNORE:
  3140. okay = false;
  3141. break;
  3142. case ACCEPT_IF_APK:
  3143. // If we're in accept-if-apk state, then the first file we
  3144. // see MUST be the apk.
  3145. if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
  3146. if (DEBUG) Slog.d(TAG, "APK file; installing");
  3147. // Try to install the app.
  3148. String installerName = mPackageInstallers.get(pkg);
  3149. okay = installApk(info, installerName, instream);
  3150. // good to go; promote to ACCEPT
  3151. mPackagePolicies.put(pkg, (okay)
  3152. ? RestorePolicy.ACCEPT
  3153. : RestorePolicy.IGNORE);
  3154. // At this point we've consumed this file entry
  3155. // ourselves, so just strip the tar footer and
  3156. // go on to the next file in the input stream
  3157. skipTarPadding(info.size, instream);
  3158. return true;
  3159. } else {
  3160. // File data before (or without) the apk. We can't
  3161. // handle it coherently in this case so ignore it.
  3162. mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
  3163. okay = false;
  3164. }
  3165. break;
  3166. case ACCEPT:
  3167. if (info.domain.equals(FullBackup.APK_TREE_TOKEN)) {
  3168. if (DEBUG) Slog.d(TAG, "apk present but ACCEPT");
  3169. // we can take the data without the apk, so we
  3170. // *want* to do so. skip the apk by declaring this
  3171. // one file not-okay without changing the restore
  3172. // policy for the package.
  3173. okay = false;
  3174. }
  3175. break;
  3176. default:
  3177. // Something has gone dreadfully wrong when determining
  3178. // the restore policy from the manifest. Ignore the
  3179. // rest of this package's data.
  3180. Slog.e(TAG, "Invalid policy from manifest");
  3181. okay = false;
  3182. mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
  3183. break;
  3184. }
  3185. // If the policy is satisfied, go ahead and set up to pipe the
  3186. // data to the agent.
  3187. if (DEBUG && okay && mAgent != null) {
  3188. Slog.i(TAG, "Reusing existing agent instance");
  3189. }
  3190. if (okay && mAgent == null) {
  3191. if (DEBUG) Slog.d(TAG, "Need to launch agent for " + pkg);
  3192. try {
  3193. mTargetApp = mPackageManager.getApplicationInfo(pkg, 0);
  3194. // If we haven't sent any data to this app yet, we probably
  3195. // need to clear it first. Check that.
  3196. if (!mClearedPackages.contains(pkg)) {
  3197. // apps with their own backup agents are
  3198. // responsible for coherently managing a full
  3199. // restore.
  3200. if (mTargetApp.backupAgentName == null) {
  3201. if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
  3202. clearApplicationDataSynchronous(pkg);
  3203. } else {
  3204. if (DEBUG) Slog.d(TAG, "backup agent ("
  3205. + mTargetApp.backupAgentName + ") => no clear");
  3206. }
  3207. mClearedPackages.add(pkg);
  3208. } else {
  3209. if (DEBUG) Slog.d(TAG, "We've initialized this app already; no clear required");
  3210. }
  3211. // All set; now set up the IPC and launch the agent
  3212. setUpPipes();
  3213. mAgent = bindToAgentSynchronous(mTargetApp,
  3214. IApplicationThread.BACKUP_MODE_RESTORE_FULL);
  3215. mAgentPackage = pkg;
  3216. } catch (IOException e) {
  3217. // fall through to error handling
  3218. } catch (NameNotFoundException e) {
  3219. // fall through to error handling
  3220. }
  3221. if (mAgent == null) {
  3222. if (DEBUG) Slog.d(TAG, "Unable to create agent for " + pkg);
  3223. okay = false;
  3224. tearDownPipes();
  3225. mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
  3226. }
  3227. }
  3228. // Sanity check: make sure we never give data to the wrong app. This
  3229. // should never happen but a little paranoia here won't go amiss.
  3230. if (okay && !pkg.equals(mAgentPackage)) {
  3231. Slog.e(TAG, "Restoring data for " + pkg
  3232. + " but agent is for " + mAgentPackage);
  3233. okay = false;
  3234. }
  3235. // At this point we have an agent ready to handle the full
  3236. // restore data as well as a pipe for sending data to
  3237. // that agent. Tell the agent to start reading from the
  3238. // pipe.
  3239. if (okay) {
  3240. boolean agentSuccess = true;
  3241. long toCopy = info.size;
  3242. final int token = generateToken();
  3243. try {
  3244. prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
  3245. if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
  3246. if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
  3247. + " : " + info.path);
  3248. mObbConnection.restoreObbFile(pkg, mPipes[0],
  3249. info.size, info.type, info.path, info.mode,
  3250. info.mtime, token, mBackupManagerBinder);
  3251. } else {
  3252. if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
  3253. + info.path);
  3254. // fire up the app's agent listening on the socket. If
  3255. // the agent is running in the system process we can't
  3256. // just invoke it asynchronously, so we provide a thread
  3257. // for it here.
  3258. if (mTargetApp.processName.equals("system")) {
  3259. Slog.d(TAG, "system process agent - spinning a thread");
  3260. RestoreFileRunnable runner = new RestoreFileRunnable(
  3261. mAgent, info, mPipes[0], token);
  3262. new Thread(runner).start();
  3263. } else {
  3264. mAgent.doRestoreFile(mPipes[0], info.size, info.type,
  3265. info.domain, info.path, info.mode, info.mtime,
  3266. token, mBackupManagerBinder);
  3267. }
  3268. }
  3269. } catch (IOException e) {
  3270. // couldn't dup the socket for a process-local restore
  3271. Slog.d(TAG, "Couldn't establish restore");
  3272. agentSuccess = false;
  3273. okay = false;
  3274. } catch (RemoteException e) {
  3275. // whoops, remote entity went away. We'll eat the content
  3276. // ourselves, then, and not copy it over.
  3277. Slog.e(TAG, "Agent crashed during full restore");
  3278. agentSuccess = false;
  3279. okay = false;
  3280. }
  3281. // Copy over the data if the agent is still good
  3282. if (okay) {
  3283. boolean pipeOkay = true;
  3284. FileOutputStream pipe = new FileOutputStream(
  3285. mPipes[1].getFileDescriptor());
  3286. while (toCopy > 0) {
  3287. int toRead = (toCopy > buffer.length)
  3288. ? buffer.length : (int)toCopy;
  3289. int nRead = instream.read(buffer, 0, toRead);
  3290. if (nRead >= 0) mBytes += nRead;
  3291. if (nRead <= 0) break;
  3292. toCopy -= nRead;
  3293. // send it to the output pipe as long as things
  3294. // are still good
  3295. if (pipeOkay) {
  3296. try {
  3297. pipe.write(buffer, 0, nRead);
  3298. } catch (IOException e) {
  3299. Slog.e(TAG, "Failed to write to restore pipe", e);
  3300. pipeOkay = false;
  3301. }
  3302. }
  3303. }
  3304. // done sending that file! Now we just need to consume
  3305. // the delta from info.size to the end of block.
  3306. skipTarPadding(info.size, instream);
  3307. // and now that we've sent it all, wait for the remote
  3308. // side to acknowledge receipt
  3309. agentSuccess = waitUntilOperationComplete(token);
  3310. }
  3311. // okay, if the remote end failed at any point, deal with
  3312. // it by ignoring the rest of the restore on it
  3313. if (!agentSuccess) {
  3314. mBackupHandler.removeMessages(MSG_TIMEOUT);
  3315. tearDownPipes();
  3316. tearDownAgent(mTargetApp);
  3317. mAgent = null;
  3318. mPackagePolicies.put(pkg, RestorePolicy.IGNORE);
  3319. }
  3320. }
  3321. // Problems setting up the agent communication, or an already-
  3322. // ignored package: skip to the next tar stream entry by
  3323. // reading and discarding this file.
  3324. if (!okay) {
  3325. if (DEBUG) Slog.d(TAG, "[discarding file content]");
  3326. long bytesToConsume = (info.size + 511) & ~511;
  3327. while (bytesToConsume > 0) {
  3328. int toRead = (bytesToConsume > buffer.length)
  3329. ? buffer.length : (int)bytesToConsume;
  3330. long nRead = instream.read(buffer, 0, toRead);
  3331. if (nRead >= 0) mBytes += nRead;
  3332. if (nRead <= 0) break;
  3333. bytesToConsume -= nRead;
  3334. }
  3335. }
  3336. }
  3337. }
  3338. } catch (IOException e) {
  3339. if (DEBUG) Slog.w(TAG, "io exception on restore socket read", e);
  3340. // treat as EOF
  3341. info = null;
  3342. }
  3343. return (info != null);
  3344. }
  3345. void setUpPipes() throws IOException {
  3346. mPipes = ParcelFileDescriptor.createPipe();
  3347. }
  3348. void tearDownPipes() {
  3349. if (mPipes != null) {
  3350. try {
  3351. mPipes[0].close();
  3352. mPipes[0] = null;
  3353. mPipes[1].close();
  3354. mPipes[1] = null;
  3355. } catch (IOException e) {
  3356. Slog.w(TAG, "Couldn't close agent pipes", e);
  3357. }
  3358. mPipes = null;
  3359. }
  3360. }
  3361. void tearDownAgent(ApplicationInfo app) {
  3362. if (mAgent != null) {
  3363. try {
  3364. // unbind and tidy up even on timeout or failure, just in case
  3365. mActivityManager.unbindBackupAgent(app);
  3366. // The agent was running with a stub Application object, so shut it down.
  3367. // !!! We hardcode the confirmation UI's package name here rather than use a
  3368. // manifest flag! TODO something less direct.
  3369. if (app.uid != Process.SYSTEM_UID
  3370. && !app.packageName.equals("com.android.backupconfirm")) {
  3371. if (DEBUG) Slog.d(TAG, "Killing host process");
  3372. mActivityManager.killApplicationProcess(app.processName, app.uid);
  3373. } else {
  3374. if (DEBUG) Slog.d(TAG, "Not killing after full restore");
  3375. }
  3376. } catch (RemoteException e) {
  3377. Slog.d(TAG, "Lost app trying to shut down");
  3378. }
  3379. mAgent = null;
  3380. }
  3381. }
  3382. class RestoreInstallObserver extends IPackageInstallObserver.Stub {
  3383. final AtomicBoolean mDone = new AtomicBoolean();
  3384. String mPackageName;
  3385. int mResult;
  3386. public void reset() {
  3387. synchronized (mDone) {
  3388. mDone.set(false);
  3389. }
  3390. }
  3391. public void waitForCompletion() {
  3392. synchronized (mDone) {
  3393. while (mDone.get() == false) {
  3394. try {
  3395. mDone.wait();
  3396. } catch (InterruptedException e) { }
  3397. }
  3398. }
  3399. }
  3400. int getResult() {
  3401. return mResult;
  3402. }
  3403. @Override
  3404. public void packageInstalled(String packageName, int returnCode)
  3405. throws RemoteException {
  3406. synchronized (mDone) {
  3407. mResult = returnCode;
  3408. mPackageName = packageName;
  3409. mDone.set(true);
  3410. mDone.notifyAll();
  3411. }
  3412. }
  3413. }
  3414. class RestoreDeleteObserver extends IPackageDeleteObserver.Stub {
  3415. final AtomicBoolean mDone = new AtomicBoolean();
  3416. int mResult;
  3417. public void reset() {
  3418. synchronized (mDone) {
  3419. mDone.set(false);
  3420. }
  3421. }
  3422. public void waitForCompletion() {
  3423. synchronized (mDone) {
  3424. while (mDone.get() == false) {
  3425. try {
  3426. mDone.wait();
  3427. } catch (InterruptedException e) { }
  3428. }
  3429. }
  3430. }
  3431. @Override
  3432. public void packageDeleted(String packageName, int returnCode) throws RemoteException {
  3433. synchronized (mDone) {
  3434. mResult = returnCode;
  3435. mDone.set(true);
  3436. mDone.notifyAll();
  3437. }
  3438. }
  3439. }
  3440. final RestoreInstallObserver mInstallObserver = new RestoreInstallObserver();
  3441. final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
  3442. boolean installApk(FileMetadata info, String installerPackage, InputStream instream) {
  3443. boolean okay = true;
  3444. if (DEBUG) Slog.d(TAG, "Installing from backup: " + info.packageName);
  3445. // The file content is an .apk file. Copy it out to a staging location and
  3446. // attempt to install it.
  3447. File apkFile = new File(mDataDir, info.packageName);
  3448. try {
  3449. FileOutputStream apkStream = new FileOutputStream(apkFile);
  3450. byte[] buffer = new byte[32 * 1024];
  3451. long size = info.size;
  3452. while (size > 0) {
  3453. long toRead = (buffer.length < size) ? buffer.length : size;
  3454. int didRead = instream.read(buffer, 0, (int)toRead);
  3455. if (didRead >= 0) mBytes += didRead;
  3456. apkStream.write(buffer, 0, didRead);
  3457. size -= didRead;
  3458. }
  3459. apkStream.close();
  3460. // make sure the installer can read it
  3461. apkFile.setReadable(true, false);
  3462. // Now install it
  3463. Uri packageUri = Uri.fromFile(apkFile);
  3464. mInstallObserver.reset();
  3465. mPackageManager.installPackage(packageUri, mInstallObserver,
  3466. PackageManager.INSTALL_REPLACE_EXISTING | PackageManager.INSTALL_FROM_ADB,
  3467. installerPackage);
  3468. mInstallObserver.waitForCompletion();
  3469. if (mInstallObserver.getResult() != PackageManager.INSTALL_SUCCEEDED) {
  3470. // The only time we continue to accept install of data even if the
  3471. // apk install failed is if we had already determined that we could
  3472. // accept the data regardless.
  3473. if (mPackagePolicies.get(info.packageName) != RestorePolicy.ACCEPT) {
  3474. okay = false;
  3475. }
  3476. } else {
  3477. // Okay, the install succeeded. Make sure it was the right app.
  3478. boolean uninstall = false;
  3479. if (!mInstallObserver.mPackageName.equals(info.packageName)) {
  3480. Slog.w(TAG, "Restore stream claimed to include apk for "
  3481. + info.packageName + " but apk was really "
  3482. + mInstallObserver.mPackageName);
  3483. // delete the package we just put in place; it might be fraudulent
  3484. okay = false;
  3485. uninstall = true;
  3486. } else {
  3487. try {
  3488. PackageInfo pkg = mPackageManager.getPackageInfo(info.packageName,
  3489. PackageManager.GET_SIGNATURES);
  3490. if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
  3491. Slog.w(TAG, "Restore stream contains apk of package "
  3492. + info.packageName + " but it disallows backup/restore");
  3493. okay = false;
  3494. } else {
  3495. // So far so good -- do the signatures match the manifest?
  3496. Signature[] sigs = mManifestSignatures.get(info.packageName);
  3497. if (signaturesMatch(sigs, pkg)) {
  3498. // If this is a system-uid app without a declared backup agent,
  3499. // don't restore any of the file data.
  3500. if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
  3501. && (pkg.applicationInfo.backupAgentName == null)) {
  3502. Slog.w(TAG, "Installed app " + info.packageName
  3503. + " has restricted uid and no agent");
  3504. okay = false;
  3505. }
  3506. } else {
  3507. Slog.w(TAG, "Installed app " + info.packageName
  3508. + " signatures do not match restore manifest");
  3509. okay = false;
  3510. uninstall = true;
  3511. }
  3512. }
  3513. } catch (NameNotFoundException e) {
  3514. Slog.w(TAG, "Install of package " + info.packageName
  3515. + " succeeded but now not found");
  3516. okay = false;
  3517. }
  3518. }
  3519. // If we're not okay at this point, we need to delete the package
  3520. // that we just installed.
  3521. if (uninstall) {
  3522. mDeleteObserver.reset();
  3523. mPackageManager.deletePackage(mInstallObserver.mPackageName,
  3524. mDeleteObserver, 0);
  3525. mDeleteObserver.waitForCompletion();
  3526. }
  3527. }
  3528. } catch (IOException e) {
  3529. Slog.e(TAG, "Unable to transcribe restored apk for install");
  3530. okay = false;
  3531. } finally {
  3532. apkFile.delete();
  3533. }
  3534. return okay;
  3535. }
  3536. // Given an actual file content size, consume the post-content padding mandated
  3537. // by the tar format.
  3538. void skipTarPadding(long size, InputStream instream) throws IOException {
  3539. long partial = (size + 512) % 512;
  3540. if (partial > 0) {
  3541. final int needed = 512 - (int)partial;
  3542. byte[] buffer = new byte[needed];
  3543. if (readExactly(instream, buffer, 0, needed) == needed) {
  3544. mBytes += needed;
  3545. } else throw new IOException("Unexpected EOF in padding");
  3546. }
  3547. }
  3548. // Returns a policy constant; takes a buffer arg to reduce memory churn
  3549. RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
  3550. throws IOException {
  3551. // Fail on suspiciously large manifest files
  3552. if (info.size > 64 * 1024) {
  3553. throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
  3554. }
  3555. byte[] buffer = new byte[(int) info.size];
  3556. if (readExactly(instream, buffer, 0, (int)info.size) == info.size) {
  3557. mBytes += info.size;
  3558. } else throw new IOException("Unexpected EOF in manifest");
  3559. RestorePolicy policy = RestorePolicy.IGNORE;
  3560. String[] str = new String[1];
  3561. int offset = 0;
  3562. try {
  3563. offset = extractLine(buffer, offset, str);
  3564. int version = Integer.parseInt(str[0]);
  3565. if (version == BACKUP_MANIFEST_VERSION) {
  3566. offset = extractLine(buffer, offset, str);
  3567. String manifestPackage = str[0];
  3568. // TODO: handle <original-package>
  3569. if (manifestPackage.equals(info.packageName)) {
  3570. offset = extractLine(buffer, offset, str);
  3571. version = Integer.parseInt(str[0]); // app version
  3572. offset = extractLine(buffer, offset, str);
  3573. int platformVersion = Integer.parseInt(str[0]);
  3574. offset = extractLine(buffer, offset, str);
  3575. info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
  3576. offset = extractLine(buffer, offset, str);
  3577. boolean hasApk = str[0].equals("1");
  3578. offset = extractLine(buffer, offset, str);
  3579. int numSigs = Integer.parseInt(str[0]);
  3580. if (numSigs > 0) {
  3581. Signature[] sigs = new Signature[numSigs];
  3582. for (int i = 0; i < numSigs; i++) {
  3583. offset = extractLine(buffer, offset, str);
  3584. sigs[i] = new Signature(str[0]);
  3585. }
  3586. mManifestSignatures.put(info.packageName, sigs);
  3587. // Okay, got the manifest info we need...
  3588. try {
  3589. PackageInfo pkgInfo = mPackageManager.getPackageInfo(
  3590. info.packageName, PackageManager.GET_SIGNATURES);
  3591. // Fall through to IGNORE if the app explicitly disallows backup
  3592. final int flags = pkgInfo.applicationInfo.flags;
  3593. if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
  3594. // Restore system-uid-space packages only if they have
  3595. // defined a custom backup agent
  3596. if ((pkgInfo.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
  3597. || (pkgInfo.applicationInfo.backupAgentName != null)) {
  3598. // Verify signatures against any installed version; if they
  3599. // don't match, then we fall though and ignore the data. The
  3600. // signatureMatch() method explicitly ignores the signature
  3601. // check for packages installed on the system partition, because
  3602. // such packages are signed with the platform cert instead of
  3603. // the app developer's cert, so they're different on every
  3604. // device.
  3605. if (signaturesMatch(sigs, pkgInfo)) {
  3606. if (pkgInfo.versionCode >= version) {
  3607. Slog.i(TAG, "Sig + version match; taking data");
  3608. policy = RestorePolicy.ACCEPT;
  3609. } else {
  3610. // The data is from a newer version of the app than
  3611. // is presently installed. That means we can only
  3612. // use it if the matching apk is also supplied.
  3613. Slog.d(TAG, "Data version " + version
  3614. + " is newer than installed version "
  3615. + pkgInfo.versionCode + " - requiring apk");
  3616. policy = RestorePolicy.ACCEPT_IF_APK;
  3617. }
  3618. } else {
  3619. Slog.w(TAG, "Restore manifest signatures do not match "
  3620. + "installed application for " + info.packageName);
  3621. }
  3622. } else {
  3623. Slog.w(TAG, "Package " + info.packageName
  3624. + " is system level with no agent");
  3625. }
  3626. } else {
  3627. if (DEBUG) Slog.i(TAG, "Restore manifest from "
  3628. + info.packageName + " but allowBackup=false");
  3629. }
  3630. } catch (NameNotFoundException e) {
  3631. // Okay, the target app isn't installed. We can process
  3632. // the restore properly only if the dataset provides the
  3633. // apk file and we can successfully install it.
  3634. if (DEBUG) Slog.i(TAG, "Package " + info.packageName
  3635. + " not installed; requiring apk in dataset");
  3636. policy = RestorePolicy.ACCEPT_IF_APK;
  3637. }
  3638. if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
  3639. Slog.i(TAG, "Cannot restore package " + info.packageName
  3640. + " without the matching .apk");
  3641. }
  3642. } else {
  3643. Slog.i(TAG, "Missing signature on backed-up package "
  3644. + info.packageName);
  3645. }
  3646. } else {
  3647. Slog.i(TAG, "Expected package " + info.packageName
  3648. + " but restore manifest claims " + manifestPackage);
  3649. }
  3650. } else {
  3651. Slog.i(TAG, "Unknown restore manifest version " + version
  3652. + " for package " + info.packageName);
  3653. }
  3654. } catch (NumberFormatException e) {
  3655. Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
  3656. } catch (IllegalArgumentException e) {
  3657. Slog.w(TAG, e.getMessage());
  3658. }
  3659. return policy;
  3660. }
  3661. // Builds a line from a byte buffer starting at 'offset', and returns
  3662. // the index of the next unconsumed data in the buffer.
  3663. int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
  3664. final int end = buffer.length;
  3665. if (offset >= end) throw new IOException("Incomplete data");
  3666. int pos;
  3667. for (pos = offset; pos < end; pos++) {
  3668. byte c = buffer[pos];
  3669. // at LF we declare end of line, and return the next char as the
  3670. // starting point for the next time through
  3671. if (c == '\n') {
  3672. break;
  3673. }
  3674. }
  3675. outStr[0] = new String(buffer, offset, pos - offset);
  3676. pos++; // may be pointing an extra byte past the end but that's okay
  3677. return pos;
  3678. }
  3679. void dumpFileMetadata(FileMetadata info) {
  3680. if (DEBUG) {
  3681. StringBuilder b = new StringBuilder(128);
  3682. // mode string
  3683. b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
  3684. b.append(((info.mode & 0400) != 0) ? 'r' : '-');
  3685. b.append(((info.mode & 0200) != 0) ? 'w' : '-');
  3686. b.append(((info.mode & 0100) != 0) ? 'x' : '-');
  3687. b.append(((info.mode & 0040) != 0) ? 'r' : '-');
  3688. b.append(((info.mode & 0020) != 0) ? 'w' : '-');
  3689. b.append(((info.mode & 0010) != 0) ? 'x' : '-');
  3690. b.append(((info.mode & 0004) != 0) ? 'r' : '-');
  3691. b.append(((info.mode & 0002) != 0) ? 'w' : '-');
  3692. b.append(((info.mode & 0001) != 0) ? 'x' : '-');
  3693. b.append(String.format(" %9d ", info.size));
  3694. Date stamp = new Date(info.mtime);
  3695. b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
  3696. b.append(info.packageName);
  3697. b.append(" :: ");
  3698. b.append(info.domain);
  3699. b.append(" :: ");
  3700. b.append(info.path);
  3701. Slog.i(TAG, b.toString());
  3702. }
  3703. }
  3704. // Consume a tar file header block [sequence] and accumulate the relevant metadata
  3705. FileMetadata readTarHeaders(InputStream instream) throws IOException {
  3706. byte[] block = new byte[512];
  3707. FileMetadata info = null;
  3708. boolean gotHeader = readTarHeader(instream, block);
  3709. if (gotHeader) {
  3710. try {
  3711. // okay, presume we're okay, and extract the various metadata
  3712. info = new FileMetadata();
  3713. info.size = extractRadix(block, 124, 12, 8);
  3714. info.mtime = extractRadix(block, 136, 12, 8);
  3715. info.mode = extractRadix(block, 100, 8, 8);
  3716. info.path = extractString(block, 345, 155); // prefix
  3717. String path = extractString(block, 0, 100);
  3718. if (path.length() > 0) {
  3719. if (info.path.length() > 0) info.path += '/';
  3720. info.path += path;
  3721. }
  3722. // tar link indicator field: 1 byte at offset 156 in the header.
  3723. int typeChar = block[156];
  3724. if (typeChar == 'x') {
  3725. // pax extended header, so we need to read that
  3726. gotHeader = readPaxExtendedHeader(instream, info);
  3727. if (gotHeader) {
  3728. // and after a pax extended header comes another real header -- read
  3729. // that to find the real file type
  3730. gotHeader = readTarHeader(instream, block);
  3731. }
  3732. if (!gotHeader) throw new IOException("Bad or missing pax header");
  3733. typeChar = block[156];
  3734. }
  3735. switch (typeChar) {
  3736. case '0': info.type = BackupAgent.TYPE_FILE; break;
  3737. case '5': {
  3738. info.type = BackupAgent.TYPE_DIRECTORY;
  3739. if (info.size != 0) {
  3740. Slog.w(TAG, "Directory entry with nonzero size in header");
  3741. info.size = 0;
  3742. }
  3743. break;
  3744. }
  3745. case 0: {
  3746. // presume EOF
  3747. if (DEBUG) Slog.w(TAG, "Saw type=0 in tar header block, info=" + info);
  3748. return null;
  3749. }
  3750. default: {
  3751. Slog.e(TAG, "Unknown tar entity type: " + typeChar);
  3752. throw new IOException("Unknown entity type " + typeChar);
  3753. }
  3754. }
  3755. // Parse out the path
  3756. //
  3757. // first: apps/shared/unrecognized
  3758. if (FullBackup.SHARED_PREFIX.regionMatches(0,
  3759. info.path, 0, FullBackup.SHARED_PREFIX.length())) {
  3760. // File in shared storage. !!! TODO: implement this.
  3761. info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
  3762. info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
  3763. info.domain = FullBackup.SHARED_STORAGE_TOKEN;
  3764. if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
  3765. } else if (FullBackup.APPS_PREFIX.regionMatches(0,
  3766. info.path, 0, FullBackup.APPS_PREFIX.length())) {
  3767. // App content! Parse out the package name and domain
  3768. // strip the apps/ prefix
  3769. info.path = info.path.substring(FullBackup.APPS_PREFIX.length());
  3770. // extract the package name
  3771. int slash = info.path.indexOf('/');
  3772. if (slash < 0) throw new IOException("Illegal semantic path in " + info.path);
  3773. info.packageName = info.path.substring(0, slash);
  3774. info.path = info.path.substring(slash+1);
  3775. // if it's a manifest we're done, otherwise parse out the domains
  3776. if (!info.path.equals(BACKUP_MANIFEST_FILENAME)) {
  3777. slash = info.path.indexOf('/');
  3778. if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
  3779. info.domain = info.path.substring(0, slash);
  3780. info.path = info.path.substring(slash + 1);
  3781. }
  3782. }
  3783. } catch (IOException e) {
  3784. if (DEBUG) {
  3785. Slog.e(TAG, "Parse error in header: " + e.getMessage());
  3786. HEXLOG(block);
  3787. }
  3788. throw e;
  3789. }
  3790. }
  3791. return info;
  3792. }
  3793. private void HEXLOG(byte[] block) {
  3794. int offset = 0;
  3795. int todo = block.length;
  3796. StringBuilder buf = new StringBuilder(64);
  3797. while (todo > 0) {
  3798. buf.append(String.format("%04x ", offset));
  3799. int numThisLine = (todo > 16) ? 16 : todo;
  3800. for (int i = 0; i < numThisLine; i++) {
  3801. buf.append(String.format("%02x ", block[offset+i]));
  3802. }
  3803. Slog.i("hexdump", buf.toString());
  3804. buf.setLength(0);
  3805. todo -= numThisLine;
  3806. offset += numThisLine;
  3807. }
  3808. }
  3809. // Read exactly the given number of bytes into a buffer at the stated offset.
  3810. // Returns false if EOF is encountered before the requested number of bytes
  3811. // could be read.
  3812. int readExactly(InputStream in, byte[] buffer, int offset, int size)
  3813. throws IOException {
  3814. if (size <= 0) throw new IllegalArgumentException("size must be > 0");
  3815. int soFar = 0;
  3816. while (soFar < size) {
  3817. int nRead = in.read(buffer, offset + soFar, size - soFar);
  3818. if (nRead <= 0) {
  3819. if (MORE_DEBUG) Slog.w(TAG, "- wanted exactly " + size + " but got only " + soFar);
  3820. break;
  3821. }
  3822. soFar += nRead;
  3823. }
  3824. return soFar;
  3825. }
  3826. boolean readTarHeader(InputStream instream, byte[] block) throws IOException {
  3827. final int got = readExactly(instream, block, 0, 512);
  3828. if (got == 0) return false; // Clean EOF
  3829. if (got < 512) throw new IOException("Unable to read full block header");
  3830. mBytes += 512;
  3831. return true;
  3832. }
  3833. // overwrites 'info' fields based on the pax extended header
  3834. boolean readPaxExtendedHeader(InputStream instream, FileMetadata info)
  3835. throws IOException {
  3836. // We should never see a pax extended header larger than this
  3837. if (info.size > 32*1024) {
  3838. Slog.w(TAG, "Suspiciously large pax header size " + info.size
  3839. + " - aborting");
  3840. throw new IOException("Sanity failure: pax header size " + info.size);
  3841. }
  3842. // read whole blocks, not just the content size
  3843. int numBlocks = (int)((info.size + 511) >> 9);
  3844. byte[] data = new byte[numBlocks * 512];
  3845. if (readExactly(instream, data, 0, data.length) < data.length) {
  3846. throw new IOException("Unable to read full pax header");
  3847. }
  3848. mBytes += data.length;
  3849. final int contentSize = (int) info.size;
  3850. int offset = 0;
  3851. do {
  3852. // extract the line at 'offset'
  3853. int eol = offset+1;
  3854. while (eol < contentSize && data[eol] != ' ') eol++;
  3855. if (eol >= contentSize) {
  3856. // error: we just hit EOD looking for the end of the size field
  3857. throw new IOException("Invalid pax data");
  3858. }
  3859. // eol points to the space between the count and the key
  3860. int linelen = (int) extractRadix(data, offset, eol - offset, 10);
  3861. int key = eol + 1; // start of key=value
  3862. eol = offset + linelen - 1; // trailing LF
  3863. int value;
  3864. for (value = key+1; data[value] != '=' && value <= eol; value++);
  3865. if (value > eol) {
  3866. throw new IOException("Invalid pax declaration");
  3867. }
  3868. // pax requires that key/value strings be in UTF-8
  3869. String keyStr = new String(data, key, value-key, "UTF-8");
  3870. // -1 to strip the trailing LF
  3871. String valStr = new String(data, value+1, eol-value-1, "UTF-8");
  3872. if ("path".equals(keyStr)) {
  3873. info.path = valStr;
  3874. } else if ("size".equals(keyStr)) {
  3875. info.size = Long.parseLong(valStr);
  3876. } else {
  3877. if (DEBUG) Slog.i(TAG, "Unhandled pax key: " + key);
  3878. }
  3879. offset += linelen;
  3880. } while (offset < contentSize);
  3881. return true;
  3882. }
  3883. long extractRadix(byte[] data, int offset, int maxChars, int radix)
  3884. throws IOException {
  3885. long value = 0;
  3886. final int end = offset + maxChars;
  3887. for (int i = offset; i < end; i++) {
  3888. final byte b = data[i];
  3889. // Numeric fields in tar can terminate with either NUL or SPC
  3890. if (b == 0 || b == ' ') break;
  3891. if (b < '0' || b > ('0' + radix - 1)) {
  3892. throw new IOException("Invalid number in header: '" + (char)b + "' for radix " + radix);
  3893. }
  3894. value = radix * value + (b - '0');
  3895. }
  3896. return value;
  3897. }
  3898. String extractString(byte[] data, int offset, int maxChars) throws IOException {
  3899. final int end = offset + maxChars;
  3900. int eos = offset;
  3901. // tar string fields terminate early with a NUL
  3902. while (eos < end && data[eos] != 0) eos++;
  3903. return new String(data, offset, eos-offset, "US-ASCII");
  3904. }
  3905. void sendStartRestore() {
  3906. if (mObserver != null) {
  3907. try {
  3908. mObserver.onStartRestore();
  3909. } catch (RemoteException e) {
  3910. Slog.w(TAG, "full restore observer went away: startRestore");
  3911. mObserver = null;
  3912. }
  3913. }
  3914. }
  3915. void sendOnRestorePackage(String name) {
  3916. if (mObserver != null) {
  3917. try {
  3918. // TODO: use a more user-friendly name string
  3919. mObserver.onRestorePackage(name);
  3920. } catch (RemoteException e) {
  3921. Slog.w(TAG, "full restore observer went away: restorePackage");
  3922. mObserver = null;
  3923. }
  3924. }
  3925. }
  3926. void sendEndRestore() {
  3927. if (mObserver != null) {
  3928. try {
  3929. mObserver.onEndRestore();
  3930. } catch (RemoteException e) {
  3931. Slog.w(TAG, "full restore observer went away: endRestore");
  3932. mObserver = null;
  3933. }
  3934. }
  3935. }
  3936. }
  3937. // ----- Restore handling -----
  3938. private boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
  3939. // If the target resides on the system partition, we allow it to restore
  3940. // data from the like-named package in a restore set even if the signatures
  3941. // do not match. (Unlike general applications, those flashed to the system
  3942. // partition will be signed with the device's platform certificate, so on
  3943. // different phones the same system app will have different signatures.)
  3944. if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
  3945. if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
  3946. return true;
  3947. }
  3948. // Allow unsigned apps, but not signed on one device and unsigned on the other
  3949. // !!! TODO: is this the right policy?
  3950. Signature[] deviceSigs = target.signatures;
  3951. if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
  3952. + " device=" + deviceSigs);
  3953. if ((storedSigs == null || storedSigs.length == 0)
  3954. && (deviceSigs == null || deviceSigs.length == 0)) {
  3955. return true;
  3956. }
  3957. if (storedSigs == null || deviceSigs == null) {
  3958. return false;
  3959. }
  3960. // !!! TODO: this demands that every stored signature match one
  3961. // that is present on device, and does not demand the converse.
  3962. // Is this this right policy?
  3963. int nStored = storedSigs.length;
  3964. int nDevice = deviceSigs.length;
  3965. for (int i=0; i < nStored; i++) {
  3966. boolean match = false;
  3967. for (int j=0; j < nDevice; j++) {
  3968. if (storedSigs[i].equals(deviceSigs[j])) {
  3969. match = true;
  3970. break;
  3971. }
  3972. }
  3973. if (!match) {
  3974. return false;
  3975. }
  3976. }
  3977. return true;
  3978. }
  3979. enum RestoreState {
  3980. INITIAL,
  3981. DOWNLOAD_DATA,
  3982. PM_METADATA,
  3983. RUNNING_QUEUE,
  3984. FINAL
  3985. }
  3986. class PerformRestoreTask implements BackupRestoreTask {
  3987. private IBackupTransport mTransport;
  3988. private IRestoreObserver mObserver;
  3989. private long mToken;
  3990. private PackageInfo mTargetPackage;
  3991. private File mStateDir;
  3992. private int mPmToken;
  3993. private boolean mNeedFullBackup;
  3994. private HashSet<String> mFilterSet;
  3995. private long mStartRealtime;
  3996. private PackageManagerBackupAgent mPmAgent;
  3997. private List<PackageInfo> mAgentPackages;
  3998. private ArrayList<PackageInfo> mRestorePackages;
  3999. private RestoreState mCurrentState;
  4000. private int mCount;
  4001. private boolean mFinished;
  4002. private int mStatus;
  4003. private File mBackupDataName;
  4004. private File mNewStateName;
  4005. private File mSavedStateName;
  4006. private ParcelFileDescriptor mBackupData;
  4007. private ParcelFileDescriptor mNewState;
  4008. private PackageInfo mCurrentPackage;
  4009. class RestoreRequest {
  4010. public PackageInfo app;
  4011. public int storedAppVersion;
  4012. RestoreRequest(PackageInfo _app, int _version) {
  4013. app = _app;
  4014. storedAppVersion = _version;
  4015. }
  4016. }
  4017. PerformRestoreTask(IBackupTransport transport, String dirName, IRestoreObserver observer,
  4018. long restoreSetToken, PackageInfo targetPackage, int pmToken,
  4019. boolean needFullBackup, String[] filterSet) {
  4020. mCurrentState = RestoreState.INITIAL;
  4021. mFinished = false;
  4022. mPmAgent = null;
  4023. mTransport = transport;
  4024. mObserver = observer;
  4025. mToken = restoreSetToken;
  4026. mTargetPackage = targetPackage;
  4027. mPmToken = pmToken;
  4028. mNeedFullBackup = needFullBackup;
  4029. if (filterSet != null) {
  4030. mFilterSet = new HashSet<String>();
  4031. for (String pkg : filterSet) {
  4032. mFilterSet.add(pkg);
  4033. }
  4034. } else {
  4035. mFilterSet = null;
  4036. }
  4037. mStateDir = new File(mBaseStateDir, dirName);
  4038. }
  4039. // Execute one tick of whatever state machine the task implements
  4040. @Override
  4041. public void execute() {
  4042. if (MORE_DEBUG) Slog.v(TAG, "*** Executing restore step: " + mCurrentState);
  4043. switch (mCurrentState) {
  4044. case INITIAL:
  4045. beginRestore();
  4046. break;
  4047. case DOWNLOAD_DATA:
  4048. downloadRestoreData();
  4049. break;
  4050. case PM_METADATA:
  4051. restorePmMetadata();
  4052. break;
  4053. case RUNNING_QUEUE:
  4054. restoreNextAgent();
  4055. break;
  4056. case FINAL:
  4057. if (!mFinished) finalizeRestore();
  4058. else {
  4059. Slog.e(TAG, "Duplicate finish");
  4060. }
  4061. mFinished = true;
  4062. break;
  4063. }
  4064. }
  4065. // Initialize and set up for the PM metadata restore, which comes first
  4066. void beginRestore() {
  4067. // Don't account time doing the restore as inactivity of the app
  4068. // that has opened a restore session.
  4069. mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
  4070. // Assume error until we successfully init everything
  4071. mStatus = BackupConstants.TRANSPORT_ERROR;
  4072. try {
  4073. // TODO: Log this before getAvailableRestoreSets, somehow
  4074. EventLog.writeEvent(EventLogTags.RESTORE_START, mTransport.transportDirName(), mToken);
  4075. // Get the list of all packages which have backup enabled.
  4076. // (Include the Package Manager metadata pseudo-package first.)
  4077. mRestorePackages = new ArrayList<PackageInfo>();
  4078. PackageInfo omPackage = new PackageInfo();
  4079. omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
  4080. mRestorePackages.add(omPackage);
  4081. mAgentPackages = allAgentPackages();
  4082. if (mTargetPackage == null) {
  4083. // if there's a filter set, strip out anything that isn't
  4084. // present before proceeding
  4085. if (mFilterSet != null) {
  4086. for (int i = mAgentPackages.size() - 1; i >= 0; i--) {
  4087. final PackageInfo pkg = mAgentPackages.get(i);
  4088. if (! mFilterSet.contains(pkg.packageName)) {
  4089. mAgentPackages.remove(i);
  4090. }
  4091. }
  4092. if (MORE_DEBUG) {
  4093. Slog.i(TAG, "Post-filter package set for restore:");
  4094. for (PackageInfo p : mAgentPackages) {
  4095. Slog.i(TAG, " " + p);
  4096. }
  4097. }
  4098. }
  4099. mRestorePackages.addAll(mAgentPackages);
  4100. } else {
  4101. // Just one package to attempt restore of
  4102. mRestorePackages.add(mTargetPackage);
  4103. }
  4104. // let the observer know that we're running
  4105. if (mObserver != null) {
  4106. try {
  4107. // !!! TODO: get an actual count from the transport after
  4108. // its startRestore() runs?
  4109. mObserver.restoreStarting(mRestorePackages.size());
  4110. } catch (RemoteException e) {
  4111. Slog.d(TAG, "Restore observer died at restoreStarting");
  4112. mObserver = null;
  4113. }
  4114. }
  4115. } catch (RemoteException e) {
  4116. // Something has gone catastrophically wrong with the transport
  4117. Slog.e(TAG, "Error communicating with transport for restore");
  4118. executeNextState(RestoreState.FINAL);
  4119. return;
  4120. }
  4121. mStatus = BackupConstants.TRANSPORT_OK;
  4122. executeNextState(RestoreState.DOWNLOAD_DATA);
  4123. }
  4124. void downloadRestoreData() {
  4125. // Note that the download phase can be very time consuming, but we're executing
  4126. // it inline here on the looper. This is "okay" because it is not calling out to
  4127. // third party code; the transport is "trusted," and so we assume it is being a
  4128. // good citizen and timing out etc when appropriate.
  4129. //
  4130. // TODO: when appropriate, move the download off the looper and rearrange the
  4131. // error handling around that.
  4132. try {
  4133. mStatus = mTransport.startRestore(mToken,
  4134. mRestorePackages.toArray(new PackageInfo[0]));
  4135. if (mStatus != BackupConstants.TRANSPORT_OK) {
  4136. Slog.e(TAG, "Error starting restore operation");
  4137. EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  4138. executeNextState(RestoreState.FINAL);
  4139. return;
  4140. }
  4141. } catch (RemoteException e) {
  4142. Slog.e(TAG, "Error communicating with transport for restore");
  4143. EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  4144. mStatus = BackupConstants.TRANSPORT_ERROR;
  4145. executeNextState(RestoreState.FINAL);
  4146. return;
  4147. }
  4148. // Successful download of the data to be parceled out to the apps, so off we go.
  4149. executeNextState(RestoreState.PM_METADATA);
  4150. }
  4151. void restorePmMetadata() {
  4152. try {
  4153. String packageName = mTransport.nextRestorePackage();
  4154. if (packageName == null) {
  4155. Slog.e(TAG, "Error getting first restore package");
  4156. EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  4157. mStatus = BackupConstants.TRANSPORT_ERROR;
  4158. executeNextState(RestoreState.FINAL);
  4159. return;
  4160. } else if (packageName.equals("")) {
  4161. Slog.i(TAG, "No restore data available");
  4162. int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
  4163. EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, 0, millis);
  4164. mStatus = BackupConstants.TRANSPORT_OK;
  4165. executeNextState(RestoreState.FINAL);
  4166. return;
  4167. } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
  4168. Slog.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
  4169. + "\", found only \"" + packageName + "\"");
  4170. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
  4171. "Package manager data missing");
  4172. executeNextState(RestoreState.FINAL);
  4173. return;
  4174. }
  4175. // Pull the Package Manager metadata from the restore set first
  4176. PackageInfo omPackage = new PackageInfo();
  4177. omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
  4178. mPmAgent = new PackageManagerBackupAgent(
  4179. mPackageManager, mAgentPackages);
  4180. initiateOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(mPmAgent.onBind()),
  4181. mNeedFullBackup);
  4182. // The PM agent called operationComplete() already, because our invocation
  4183. // of it is process-local and therefore synchronous. That means that a
  4184. // RUNNING_QUEUE message is already enqueued. Only if we're unable to
  4185. // proceed with running the queue do we remove that pending message and
  4186. // jump straight to the FINAL state.
  4187. // Verify that the backup set includes metadata. If not, we can't do
  4188. // signature/version verification etc, so we simply do not proceed with
  4189. // the restore operation.
  4190. if (!mPmAgent.hasMetadata()) {
  4191. Slog.e(TAG, "No restore metadata available, so not restoring settings");
  4192. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
  4193. "Package manager restore metadata missing");
  4194. mStatus = BackupConstants.TRANSPORT_ERROR;
  4195. mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
  4196. executeNextState(RestoreState.FINAL);
  4197. return;
  4198. }
  4199. } catch (RemoteException e) {
  4200. Slog.e(TAG, "Error communicating with transport for restore");
  4201. EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  4202. mStatus = BackupConstants.TRANSPORT_ERROR;
  4203. mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
  4204. executeNextState(RestoreState.FINAL);
  4205. return;
  4206. }
  4207. // Metadata is intact, so we can now run the restore queue. If we get here,
  4208. // we have already enqueued the necessary next-step message on the looper.
  4209. }
  4210. void restoreNextAgent() {
  4211. try {
  4212. String packageName = mTransport.nextRestorePackage();
  4213. if (packageName == null) {
  4214. Slog.e(TAG, "Error getting next restore package");
  4215. EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  4216. executeNextState(RestoreState.FINAL);
  4217. return;
  4218. } else if (packageName.equals("")) {
  4219. if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
  4220. int millis = (int) (SystemClock.elapsedRealtime() - mStartRealtime);
  4221. EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, mCount, millis);
  4222. executeNextState(RestoreState.FINAL);
  4223. return;
  4224. }
  4225. if (mObserver != null) {
  4226. try {
  4227. mObserver.onUpdate(mCount, packageName);
  4228. } catch (RemoteException e) {
  4229. Slog.d(TAG, "Restore observer died in onUpdate");
  4230. mObserver = null;
  4231. }
  4232. }
  4233. Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
  4234. if (metaInfo == null) {
  4235. Slog.e(TAG, "Missing metadata for " + packageName);
  4236. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
  4237. "Package metadata missing");
  4238. executeNextState(RestoreState.RUNNING_QUEUE);
  4239. return;
  4240. }
  4241. PackageInfo packageInfo;
  4242. try {
  4243. int flags = PackageManager.GET_SIGNATURES;
  4244. packageInfo = mPackageManager.getPackageInfo(packageName, flags);
  4245. } catch (NameNotFoundException e) {
  4246. Slog.e(TAG, "Invalid package restoring data", e);
  4247. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
  4248. "Package missing on device");
  4249. executeNextState(RestoreState.RUNNING_QUEUE);
  4250. return;
  4251. }
  4252. if (packageInfo.applicationInfo.backupAgentName == null
  4253. || "".equals(packageInfo.applicationInfo.backupAgentName)) {
  4254. if (DEBUG) {
  4255. Slog.i(TAG, "Data exists for package " + packageName
  4256. + " but app has no agent; skipping");
  4257. }
  4258. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
  4259. "Package has no agent");
  4260. executeNextState(RestoreState.RUNNING_QUEUE);
  4261. return;
  4262. }
  4263. if (metaInfo.versionCode > packageInfo.versionCode) {
  4264. // Data is from a "newer" version of the app than we have currently
  4265. // installed. If the app has not declared that it is prepared to
  4266. // handle this case, we do not attempt the restore.
  4267. if ((packageInfo.applicationInfo.flags
  4268. & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
  4269. String message = "Version " + metaInfo.versionCode
  4270. + " > installed version " + packageInfo.versionCode;
  4271. Slog.w(TAG, "Package " + packageName + ": " + message);
  4272. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
  4273. packageName, message);
  4274. executeNextState(RestoreState.RUNNING_QUEUE);
  4275. return;
  4276. } else {
  4277. if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
  4278. + " > installed " + packageInfo.versionCode
  4279. + " but restoreAnyVersion");
  4280. }
  4281. }
  4282. if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
  4283. Slog.w(TAG, "Signature mismatch restoring " + packageName);
  4284. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
  4285. "Signature mismatch");
  4286. executeNextState(RestoreState.RUNNING_QUEUE);
  4287. return;
  4288. }
  4289. if (DEBUG) Slog.v(TAG, "Package " + packageName
  4290. + " restore version [" + metaInfo.versionCode
  4291. + "] is compatible with installed version ["
  4292. + packageInfo.versionCode + "]");
  4293. // Then set up and bind the agent
  4294. IBackupAgent agent = bindToAgentSynchronous(
  4295. packageInfo.applicationInfo,
  4296. IApplicationThread.BACKUP_MODE_INCREMENTAL);
  4297. if (agent == null) {
  4298. Slog.w(TAG, "Can't find backup agent for " + packageName);
  4299. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
  4300. "Restore agent missing");
  4301. executeNextState(RestoreState.RUNNING_QUEUE);
  4302. return;
  4303. }
  4304. // And then finally start the restore on this agent
  4305. try {
  4306. initiateOneRestore(packageInfo, metaInfo.versionCode, agent, mNeedFullBackup);
  4307. ++mCount;
  4308. } catch (Exception e) {
  4309. Slog.e(TAG, "Error when attempting restore: " + e.toString());
  4310. agentErrorCleanup();
  4311. executeNextState(RestoreState.RUNNING_QUEUE);
  4312. }
  4313. } catch (RemoteException e) {
  4314. Slog.e(TAG, "Unable to fetch restore data from transport");
  4315. mStatus = BackupConstants.TRANSPORT_ERROR;
  4316. executeNextState(RestoreState.FINAL);
  4317. }
  4318. }
  4319. void finalizeRestore() {
  4320. if (MORE_DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
  4321. try {
  4322. mTransport.finishRestore();
  4323. } catch (RemoteException e) {
  4324. Slog.e(TAG, "Error finishing restore", e);
  4325. }
  4326. if (mObserver != null) {
  4327. try {
  4328. mObserver.restoreFinished(mStatus);
  4329. } catch (RemoteException e) {
  4330. Slog.d(TAG, "Restore observer died at restoreFinished");
  4331. }
  4332. }
  4333. // If this was a restoreAll operation, record that this was our
  4334. // ancestral dataset, as well as the set of apps that are possibly
  4335. // restoreable from the dataset
  4336. if (mTargetPackage == null && mPmAgent != null) {
  4337. mAncestralPackages = mPmAgent.getRestoredPackages();
  4338. mAncestralToken = mToken;
  4339. writeRestoreTokens();
  4340. }
  4341. // We must under all circumstances tell the Package Manager to
  4342. // proceed with install notifications if it's waiting for us.
  4343. if (mPmToken > 0) {
  4344. if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
  4345. try {
  4346. mPackageManagerBinder.finishPackageInstall(mPmToken);
  4347. } catch (RemoteException e) { /* can't happen */ }
  4348. }
  4349. // Furthermore we need to reset the session timeout clock
  4350. mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
  4351. mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT,
  4352. TIMEOUT_RESTORE_INTERVAL);
  4353. // done; we can finally release the wakelock
  4354. Slog.i(TAG, "Restore complete.");
  4355. mWakelock.release();
  4356. }
  4357. // Call asynchronously into the app, passing it the restore data. The next step
  4358. // after this is always a callback, either operationComplete() or handleTimeout().
  4359. void initiateOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
  4360. boolean needFullBackup) {
  4361. mCurrentPackage = app;
  4362. final String packageName = app.packageName;
  4363. if (DEBUG) Slog.d(TAG, "initiateOneRestore packageName=" + packageName);
  4364. // !!! TODO: get the dirs from the transport
  4365. mBackupDataName = new File(mDataDir, packageName + ".restore");
  4366. mNewStateName = new File(mStateDir, packageName + ".new");
  4367. mSavedStateName = new File(mStateDir, packageName);
  4368. final int token = generateToken();
  4369. try {
  4370. // Run the transport's restore pass
  4371. mBackupData = ParcelFileDescriptor.open(mBackupDataName,
  4372. ParcelFileDescriptor.MODE_READ_WRITE |
  4373. ParcelFileDescriptor.MODE_CREATE |
  4374. ParcelFileDescriptor.MODE_TRUNCATE);
  4375. if (!SELinux.restorecon(mBackupDataName)) {
  4376. Slog.e(TAG, "SElinux restorecon failed for " + mBackupDataName);
  4377. }
  4378. if (mTransport.getRestoreData(mBackupData) != BackupConstants.TRANSPORT_OK) {
  4379. // Transport-level failure, so we wind everything up and
  4380. // terminate the restore operation.
  4381. Slog.e(TAG, "Error getting restore data for " + packageName);
  4382. EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
  4383. mBackupData.close();
  4384. mBackupDataName.delete();
  4385. executeNextState(RestoreState.FINAL);
  4386. return;
  4387. }
  4388. // Okay, we have the data. Now have the agent do the restore.
  4389. mBackupData.close();
  4390. mBackupData = ParcelFileDescriptor.open(mBackupDataName,
  4391. ParcelFileDescriptor.MODE_READ_ONLY);
  4392. mNewState = ParcelFileDescriptor.open(mNewStateName,
  4393. ParcelFileDescriptor.MODE_READ_WRITE |
  4394. ParcelFileDescriptor.MODE_CREATE |
  4395. ParcelFileDescriptor.MODE_TRUNCATE);
  4396. // Kick off the restore, checking for hung agents
  4397. prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL, this);
  4398. agent.doRestore(mBackupData, appVersionCode, mNewState, token, mBackupManagerBinder);
  4399. } catch (Exception e) {
  4400. Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
  4401. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, e.toString());
  4402. agentErrorCleanup(); // clears any pending timeout messages as well
  4403. // After a restore failure we go back to running the queue. If there
  4404. // are no more packages to be restored that will be handled by the
  4405. // next step.
  4406. executeNextState(RestoreState.RUNNING_QUEUE);
  4407. }
  4408. }
  4409. void agentErrorCleanup() {
  4410. // If the agent fails restore, it might have put the app's data
  4411. // into an incoherent state. For consistency we wipe its data
  4412. // again in this case before continuing with normal teardown
  4413. clearApplicationDataSynchronous(mCurrentPackage.packageName);
  4414. agentCleanup();
  4415. }
  4416. void agentCleanup() {
  4417. mBackupDataName.delete();
  4418. try { if (mBackupData != null) mBackupData.close(); } catch (IOException e) {}
  4419. try { if (mNewState != null) mNewState.close(); } catch (IOException e) {}
  4420. mBackupData = mNewState = null;
  4421. // if everything went okay, remember the recorded state now
  4422. //
  4423. // !!! TODO: the restored data should be migrated on the server
  4424. // side into the current dataset. In that case the new state file
  4425. // we just created would reflect the data already extant in the
  4426. // backend, so there'd be nothing more to do. Until that happens,
  4427. // however, we need to make sure that we record the data to the
  4428. // current backend dataset. (Yes, this means shipping the data over
  4429. // the wire in both directions. That's bad, but consistency comes
  4430. // first, then efficiency.) Once we introduce server-side data
  4431. // migration to the newly-restored device's dataset, we will change
  4432. // the following from a discard of the newly-written state to the
  4433. // "correct" operation of renaming into the canonical state blob.
  4434. mNewStateName.delete(); // TODO: remove; see above comment
  4435. //mNewStateName.renameTo(mSavedStateName); // TODO: replace with this
  4436. // If this wasn't the PM pseudopackage, tear down the agent side
  4437. if (mCurrentPackage.applicationInfo != null) {
  4438. // unbind and tidy up even on timeout or failure
  4439. try {
  4440. mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
  4441. // The agent was probably running with a stub Application object,
  4442. // which isn't a valid run mode for the main app logic. Shut
  4443. // down the app so that next time it's launched, it gets the
  4444. // usual full initialization. Note that this is only done for
  4445. // full-system restores: when a single app has requested a restore,
  4446. // it is explicitly not killed following that operation.
  4447. if (mTargetPackage == null && (mCurrentPackage.applicationInfo.flags
  4448. & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
  4449. if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
  4450. + mCurrentPackage.applicationInfo.processName);
  4451. mActivityManager.killApplicationProcess(
  4452. mCurrentPackage.applicationInfo.processName,
  4453. mCurrentPackage.applicationInfo.uid);
  4454. }
  4455. } catch (RemoteException e) {
  4456. // can't happen; we run in the same process as the activity manager
  4457. }
  4458. }
  4459. // The caller is responsible for reestablishing the state machine; our
  4460. // responsibility here is to clear the decks for whatever comes next.
  4461. mBackupHandler.removeMessages(MSG_TIMEOUT, this);
  4462. synchronized (mCurrentOpLock) {
  4463. mCurrentOperations.clear();
  4464. }
  4465. }
  4466. // A call to agent.doRestore() has been positively acknowledged as complete
  4467. @Override
  4468. public void operationComplete() {
  4469. int size = (int) mBackupDataName.length();
  4470. EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, mCurrentPackage.packageName, size);
  4471. // Just go back to running the restore queue
  4472. agentCleanup();
  4473. executeNextState(RestoreState.RUNNING_QUEUE);
  4474. }
  4475. // A call to agent.doRestore() has timed out
  4476. @Override
  4477. public void handleTimeout() {
  4478. Slog.e(TAG, "Timeout restoring application " + mCurrentPackage.packageName);
  4479. EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
  4480. mCurrentPackage.packageName, "restore timeout");
  4481. // Handle like an agent that threw on invocation: wipe it and go on to the next
  4482. agentErrorCleanup();
  4483. executeNextState(RestoreState.RUNNING_QUEUE);
  4484. }
  4485. void executeNextState(RestoreState nextState) {
  4486. if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
  4487. + this + " nextState=" + nextState);
  4488. mCurrentState = nextState;
  4489. Message msg = mBackupHandler.obtainMessage(MSG_BACKUP_RESTORE_STEP, this);
  4490. mBackupHandler.sendMessage(msg);
  4491. }
  4492. }
  4493. class PerformClearTask implements Runnable {
  4494. IBackupTransport mTransport;
  4495. PackageInfo mPackage;
  4496. PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
  4497. mTransport = transport;
  4498. mPackage = packageInfo;
  4499. }
  4500. public void run() {
  4501. try {
  4502. // Clear the on-device backup state to ensure a full backup next time
  4503. File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
  4504. File stateFile = new File(stateDir, mPackage.packageName);
  4505. stateFile.delete();
  4506. // Tell the transport to remove all the persistent storage for the app
  4507. // TODO - need to handle failures
  4508. mTransport.clearBackupData(mPackage);
  4509. } catch (RemoteException e) {
  4510. // can't happen; the transport is local
  4511. } catch (Exception e) {
  4512. Slog.e(TAG, "Transport threw attempting to clear data for " + mPackage);
  4513. } finally {
  4514. try {
  4515. // TODO - need to handle failures
  4516. mTransport.finishBackup();
  4517. } catch (RemoteException e) {
  4518. // can't happen; the transport is local
  4519. }
  4520. // Last but not least, release the cpu
  4521. mWakelock.release();
  4522. }
  4523. }
  4524. }
  4525. class PerformInitializeTask implements Runnable {
  4526. HashSet<String> mQueue;
  4527. PerformInitializeTask(HashSet<String> transportNames) {
  4528. mQueue = transportNames;
  4529. }
  4530. public void run() {
  4531. try {
  4532. for (String transportName : mQueue) {
  4533. IBackupTransport transport = getTransport(transportName);
  4534. if (transport == null) {
  4535. Slog.e(TAG, "Requested init for " + transportName + " but not found");
  4536. continue;
  4537. }
  4538. Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
  4539. EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
  4540. long startRealtime = SystemClock.elapsedRealtime();
  4541. int status = transport.initializeDevice();
  4542. if (status == BackupConstants.TRANSPORT_OK) {
  4543. status = transport.finishBackup();
  4544. }
  4545. // Okay, the wipe really happened. Clean up our local bookkeeping.
  4546. if (status == BackupConstants.TRANSPORT_OK) {
  4547. Slog.i(TAG, "Device init successful");
  4548. int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
  4549. EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
  4550. resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
  4551. EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
  4552. synchronized (mQueueLock) {
  4553. recordInitPendingLocked(false, transportName);
  4554. }
  4555. } else {
  4556. // If this didn't work, requeue this one and try again
  4557. // after a suitable interval
  4558. Slog.e(TAG, "Transport error in initializeDevice()");
  4559. EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
  4560. synchronized (mQueueLock) {
  4561. recordInitPendingLocked(true, transportName);
  4562. }
  4563. // do this via another alarm to make sure of the wakelock states
  4564. long delay = transport.requestBackupTime();
  4565. if (DEBUG) Slog.w(TAG, "init failed on "
  4566. + transportName + " resched in " + delay);
  4567. mAlarmManager.set(AlarmManager.RTC_WAKEUP,
  4568. System.currentTimeMillis() + delay, mRunInitIntent);
  4569. }
  4570. }
  4571. } catch (RemoteException e) {
  4572. // can't happen; the transports are local
  4573. } catch (Exception e) {
  4574. Slog.e(TAG, "Unexpected error performing init", e);
  4575. } finally {
  4576. // Done; release the wakelock
  4577. mWakelock.release();
  4578. }
  4579. }
  4580. }
  4581. private void dataChangedImpl(String packageName) {
  4582. HashSet<String> targets = dataChangedTargets(packageName);
  4583. dataChangedImpl(packageName, targets);
  4584. }
  4585. private void dataChangedImpl(String packageName, HashSet<String> targets) {
  4586. // Record that we need a backup pass for the caller. Since multiple callers
  4587. // may share a uid, we need to note all candidates within that uid and schedule
  4588. // a backup pass for each of them.
  4589. EventLog.writeEvent(EventLogTags.BACKUP_DATA_CHANGED, packageName);
  4590. if (targets == null) {
  4591. Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
  4592. + " uid=" + Binder.getCallingUid());
  4593. return;
  4594. }
  4595. synchronized (mQueueLock) {
  4596. // Note that this client has made data changes that need to be backed up
  4597. if (targets.contains(packageName)) {
  4598. // Add the caller to the set of pending backups. If there is
  4599. // one already there, then overwrite it, but no harm done.
  4600. BackupRequest req = new BackupRequest(packageName);
  4601. if (mPendingBackups.put(packageName, req) == null) {
  4602. if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
  4603. // Journal this request in case of crash. The put()
  4604. // operation returned null when this package was not already
  4605. // in the set; we want to avoid touching the disk redundantly.
  4606. writeToJournalLocked(packageName);
  4607. if (MORE_DEBUG) {
  4608. int numKeys = mPendingBackups.size();
  4609. Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
  4610. for (BackupRequest b : mPendingBackups.values()) {
  4611. Slog.d(TAG, " + " + b);
  4612. }
  4613. }
  4614. }
  4615. }
  4616. }
  4617. }
  4618. // Note: packageName is currently unused, but may be in the future
  4619. private HashSet<String> dataChangedTargets(String packageName) {
  4620. // If the caller does not hold the BACKUP permission, it can only request a
  4621. // backup of its own data.
  4622. if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
  4623. Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
  4624. synchronized (mBackupParticipants) {
  4625. return mBackupParticipants.get(Binder.getCallingUid());
  4626. }
  4627. }
  4628. // a caller with full permission can ask to back up any participating app
  4629. // !!! TODO: allow backup of ANY app?
  4630. HashSet<String> targets = new HashSet<String>();
  4631. synchronized (mBackupParticipants) {
  4632. int N = mBackupParticipants.size();
  4633. for (int i = 0; i < N; i++) {
  4634. HashSet<String> s = mBackupParticipants.valueAt(i);
  4635. if (s != null) {
  4636. targets.addAll(s);
  4637. }
  4638. }
  4639. }
  4640. return targets;
  4641. }
  4642. private void writeToJournalLocked(String str) {
  4643. RandomAccessFile out = null;
  4644. try {
  4645. if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
  4646. out = new RandomAccessFile(mJournal, "rws");
  4647. out.seek(out.length());
  4648. out.writeUTF(str);
  4649. } catch (IOException e) {
  4650. Slog.e(TAG, "Can't write " + str + " to backup journal", e);
  4651. mJournal = null;
  4652. } finally {
  4653. try { if (out != null) out.close(); } catch (IOException e) {}
  4654. }
  4655. }
  4656. // ----- IBackupManager binder interface -----
  4657. public void dataChanged(final String packageName) {
  4658. final int callingUserHandle = UserHandle.getCallingUserId();
  4659. if (callingUserHandle != UserHandle.USER_OWNER) {
  4660. // App is running under a non-owner user profile. For now, we do not back
  4661. // up data from secondary user profiles.
  4662. // TODO: backups for all user profiles.
  4663. if (MORE_DEBUG) {
  4664. Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
  4665. + callingUserHandle);
  4666. }
  4667. return;
  4668. }
  4669. final HashSet<String> targets = dataChangedTargets(packageName);
  4670. if (targets == null) {
  4671. Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
  4672. + " uid=" + Binder.getCallingUid());
  4673. return;
  4674. }
  4675. mBackupHandler.post(new Runnable() {
  4676. public void run() {
  4677. dataChangedImpl(packageName, targets);
  4678. }
  4679. });
  4680. }
  4681. // Clear the given package's backup data from the current transport
  4682. public void clearBackupData(String transportName, String packageName) {
  4683. if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
  4684. PackageInfo info;
  4685. try {
  4686. info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
  4687. } catch (NameNotFoundException e) {
  4688. Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
  4689. return;
  4690. }
  4691. // If the caller does not hold the BACKUP permission, it can only request a
  4692. // wipe of its own backed-up data.
  4693. HashSet<String> apps;
  4694. if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
  4695. Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
  4696. apps = mBackupParticipants.get(Binder.getCallingUid());
  4697. } else {
  4698. // a caller with full permission can ask to back up any participating app
  4699. // !!! TODO: allow data-clear of ANY app?
  4700. if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
  4701. apps = new HashSet<String>();
  4702. int N = mBackupParticipants.size();
  4703. for (int i = 0; i < N; i++) {
  4704. HashSet<String> s = mBackupParticipants.valueAt(i);
  4705. if (s != null) {
  4706. apps.addAll(s);
  4707. }
  4708. }
  4709. }
  4710. // Is the given app an available participant?
  4711. if (apps.contains(packageName)) {
  4712. // found it; fire off the clear request
  4713. if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
  4714. mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
  4715. synchronized (mQueueLock) {
  4716. final IBackupTransport transport = getTransport(transportName);
  4717. if (transport == null) {
  4718. // transport is currently unavailable -- make sure to retry
  4719. Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
  4720. new ClearRetryParams(transportName, packageName));
  4721. mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
  4722. return;
  4723. }
  4724. long oldId = Binder.clearCallingIdentity();
  4725. mWakelock.acquire();
  4726. Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
  4727. new ClearParams(transport, info));
  4728. mBackupHandler.sendMessage(msg);
  4729. Binder.restoreCallingIdentity(oldId);
  4730. }
  4731. }
  4732. }
  4733. // Run a backup pass immediately for any applications that have declared
  4734. // that they have pending updates.
  4735. public void backupNow() {
  4736. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
  4737. if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
  4738. synchronized (mQueueLock) {
  4739. // Because the alarms we are using can jitter, and we want an *immediate*
  4740. // backup pass to happen, we restart the timer beginning with "next time,"
  4741. // then manually fire the backup trigger intent ourselves.
  4742. startBackupAlarmsLocked(BACKUP_INTERVAL);
  4743. try {
  4744. mRunBackupIntent.send();
  4745. } catch (PendingIntent.CanceledException e) {
  4746. // should never happen
  4747. Slog.e(TAG, "run-backup intent cancelled!");
  4748. }
  4749. }
  4750. }
  4751. boolean deviceIsProvisioned() {
  4752. final ContentResolver resolver = mContext.getContentResolver();
  4753. return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
  4754. }
  4755. // Run a *full* backup pass for the given package, writing the resulting data stream
  4756. // to the supplied file descriptor. This method is synchronous and does not return
  4757. // to the caller until the backup has been completed.
  4758. public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
  4759. boolean includeObbs, boolean includeShared,
  4760. boolean doAllApps, boolean includeSystem, String[] pkgList) {
  4761. mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
  4762. final int callingUserHandle = UserHandle.getCallingUserId();
  4763. if (callingUserHandle != UserHandle.USER_OWNER) {
  4764. throw new IllegalStateException("Backup supported only for the device owner");
  4765. }
  4766. // Validate
  4767. if (!doAllApps) {
  4768. if (!includeShared) {
  4769. // If we're backing up shared data (sdcard or equivalent), then we can run
  4770. // without any supplied app names. Otherwise, we'd be doing no work, so
  4771. // report the error.
  4772. if (pkgList == null || pkgList.length == 0) {
  4773. throw new IllegalArgumentException(
  4774. "Backup requested but neither shared nor any apps named");
  4775. }
  4776. }
  4777. }
  4778. long oldId = Binder.clearCallingIdentity();
  4779. try {
  4780. // Doesn't make sense to do a full backup prior to setup
  4781. if (!deviceIsProvisioned()) {
  4782. Slog.i(TAG, "Full backup not supported before setup");
  4783. return;
  4784. }
  4785. if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
  4786. + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
  4787. + " pkgs=" + pkgList);
  4788. Slog.i(TAG, "Beginning full backup...");
  4789. FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
  4790. includeShared, doAllApps, includeSystem, pkgList);
  4791. final int token = generateToken();
  4792. synchronized (mFullConfirmations) {
  4793. mFullConfirmations.put(token, params);
  4794. }
  4795. // start up the confirmation UI
  4796. if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token);
  4797. if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {
  4798. Slog.e(TAG, "Unable to launch full backup confirmation");
  4799. mFullConfirmations.delete(token);
  4800. return;
  4801. }
  4802. // make sure the screen is lit for the user interaction
  4803. mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
  4804. // start the confirmation countdown
  4805. startConfirmationTimeout(token, params);
  4806. // wait for the backup to be performed
  4807. if (DEBUG) Slog.d(TAG, "Waiting for full backup completion...");
  4808. waitForCompletion(params);
  4809. } finally {
  4810. try {
  4811. fd.close();
  4812. } catch (IOException e) {
  4813. // just eat it
  4814. }
  4815. Binder.restoreCallingIdentity(oldId);
  4816. Slog.d(TAG, "Full backup processing complete.");
  4817. }
  4818. }
  4819. public void fullRestore(ParcelFileDescriptor fd) {
  4820. mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
  4821. final int callingUserHandle = UserHandle.getCallingUserId();
  4822. if (callingUserHandle != UserHandle.USER_OWNER) {
  4823. throw new IllegalStateException("Restore supported only for the device owner");
  4824. }
  4825. long oldId = Binder.clearCallingIdentity();
  4826. try {
  4827. // Check whether the device has been provisioned -- we don't handle
  4828. // full restores prior to completing the setup process.
  4829. if (!deviceIsProvisioned()) {
  4830. Slog.i(TAG, "Full restore not permitted before setup");
  4831. return;
  4832. }
  4833. Slog.i(TAG, "Beginning full restore...");
  4834. FullRestoreParams params = new FullRestoreParams(fd);
  4835. final int token = generateToken();
  4836. synchronized (mFullConfirmations) {
  4837. mFullConfirmations.put(token, params);
  4838. }
  4839. // start up the confirmation UI
  4840. if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token);
  4841. if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) {
  4842. Slog.e(TAG, "Unable to launch full restore confirmation");
  4843. mFullConfirmations.delete(token);
  4844. return;
  4845. }
  4846. // make sure the screen is lit for the user interaction
  4847. mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
  4848. // start the confirmation countdown
  4849. startConfirmationTimeout(token, params);
  4850. // wait for the restore to be performed
  4851. if (DEBUG) Slog.d(TAG, "Waiting for full restore completion...");
  4852. waitForCompletion(params);
  4853. } finally {
  4854. try {
  4855. fd.close();
  4856. } catch (IOException e) {
  4857. Slog.w(TAG, "Error trying to close fd after full restore: " + e);
  4858. }
  4859. Binder.restoreCallingIdentity(oldId);
  4860. Slog.i(TAG, "Full restore processing complete.");
  4861. }
  4862. }
  4863. boolean startConfirmationUi(int token, String action) {
  4864. try {
  4865. Intent confIntent = new Intent(action);
  4866. confIntent.setClassName("com.android.backupconfirm",
  4867. "com.android.backupconfirm.BackupRestoreConfirmation");
  4868. confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
  4869. confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  4870. mContext.startActivity(confIntent);
  4871. } catch (ActivityNotFoundException e) {
  4872. return false;
  4873. }
  4874. return true;
  4875. }
  4876. void startConfirmationTimeout(int token, FullParams params) {
  4877. if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
  4878. + TIMEOUT_FULL_CONFIRMATION + " millis");
  4879. Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
  4880. token, 0, params);
  4881. mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
  4882. }
  4883. void waitForCompletion(FullParams params) {
  4884. synchronized (params.latch) {
  4885. while (params.latch.get() == false) {
  4886. try {
  4887. params.latch.wait();
  4888. } catch (InterruptedException e) { /* never interrupted */ }
  4889. }
  4890. }
  4891. }
  4892. void signalFullBackupRestoreCompletion(FullParams params) {
  4893. synchronized (params.latch) {
  4894. params.latch.set(true);
  4895. params.latch.notifyAll();
  4896. }
  4897. }
  4898. // Confirm that the previously-requested full backup/restore operation can proceed. This
  4899. // is used to require a user-facing disclosure about the operation.
  4900. @Override
  4901. public void acknowledgeFullBackupOrRestore(int token, boolean allow,
  4902. String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
  4903. if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token
  4904. + " allow=" + allow);
  4905. // TODO: possibly require not just this signature-only permission, but even
  4906. // require that the specific designated confirmation-UI app uid is the caller?
  4907. mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeFullBackupOrRestore");
  4908. long oldId = Binder.clearCallingIdentity();
  4909. try {
  4910. FullParams params;
  4911. synchronized (mFullConfirmations) {
  4912. params = mFullConfirmations.get(token);
  4913. if (params != null) {
  4914. mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);
  4915. mFullConfirmations.delete(token);
  4916. if (allow) {
  4917. final int verb = params instanceof FullBackupParams
  4918. ? MSG_RUN_FULL_BACKUP
  4919. : MSG_RUN_FULL_RESTORE;
  4920. params.observer = observer;
  4921. params.curPassword = curPassword;
  4922. boolean isEncrypted;
  4923. try {
  4924. isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
  4925. if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
  4926. } catch (RemoteException e) {
  4927. // couldn't contact the mount service; fail "safe" and assume encryption
  4928. Slog.e(TAG, "Unable to contact mount service!");
  4929. isEncrypted = true;
  4930. }
  4931. params.encryptPassword = (isEncrypted) ? curPassword : encPpassword;
  4932. if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
  4933. mWakelock.acquire();
  4934. Message msg = mBackupHandler.obtainMessage(verb, params);
  4935. mBackupHandler.sendMessage(msg);
  4936. } else {
  4937. Slog.w(TAG, "User rejected full backup/restore operation");
  4938. // indicate completion without having actually transferred any data
  4939. signalFullBackupRestoreCompletion(params);
  4940. }
  4941. } else {
  4942. Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
  4943. }
  4944. }
  4945. } finally {
  4946. Binder.restoreCallingIdentity(oldId);
  4947. }
  4948. }
  4949. // Enable/disable the backup service
  4950. @Override
  4951. public void setBackupEnabled(boolean enable) {
  4952. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  4953. "setBackupEnabled");
  4954. Slog.i(TAG, "Backup enabled => " + enable);
  4955. long oldId = Binder.clearCallingIdentity();
  4956. try {
  4957. boolean wasEnabled = mEnabled;
  4958. synchronized (this) {
  4959. Settings.Secure.putInt(mContext.getContentResolver(),
  4960. Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
  4961. mEnabled = enable;
  4962. }
  4963. synchronized (mQueueLock) {
  4964. if (enable && !wasEnabled && mProvisioned) {
  4965. // if we've just been enabled, start scheduling backup passes
  4966. startBackupAlarmsLocked(BACKUP_INTERVAL);
  4967. } else if (!enable) {
  4968. // No longer enabled, so stop running backups
  4969. if (DEBUG) Slog.i(TAG, "Opting out of backup");
  4970. mAlarmManager.cancel(mRunBackupIntent);
  4971. // This also constitutes an opt-out, so we wipe any data for
  4972. // this device from the backend. We start that process with
  4973. // an alarm in order to guarantee wakelock states.
  4974. if (wasEnabled && mProvisioned) {
  4975. // NOTE: we currently flush every registered transport, not just
  4976. // the currently-active one.
  4977. HashSet<String> allTransports;
  4978. synchronized (mTransports) {
  4979. allTransports = new HashSet<String>(mTransports.keySet());
  4980. }
  4981. // build the set of transports for which we are posting an init
  4982. for (String transport : allTransports) {
  4983. recordInitPendingLocked(true, transport);
  4984. }
  4985. mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
  4986. mRunInitIntent);
  4987. }
  4988. }
  4989. }
  4990. } finally {
  4991. Binder.restoreCallingIdentity(oldId);
  4992. }
  4993. }
  4994. // Enable/disable automatic restore of app data at install time
  4995. public void setAutoRestore(boolean doAutoRestore) {
  4996. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  4997. "setAutoRestore");
  4998. Slog.i(TAG, "Auto restore => " + doAutoRestore);
  4999. synchronized (this) {
  5000. Settings.Secure.putInt(mContext.getContentResolver(),
  5001. Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
  5002. mAutoRestore = doAutoRestore;
  5003. }
  5004. }
  5005. // Mark the backup service as having been provisioned
  5006. public void setBackupProvisioned(boolean available) {
  5007. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5008. "setBackupProvisioned");
  5009. /*
  5010. * This is now a no-op; provisioning is simply the device's own setup state.
  5011. */
  5012. }
  5013. private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
  5014. // We used to use setInexactRepeating(), but that may be linked to
  5015. // backups running at :00 more often than not, creating load spikes.
  5016. // Schedule at an exact time for now, and also add a bit of "fuzz".
  5017. Random random = new Random();
  5018. long when = System.currentTimeMillis() + delayBeforeFirstBackup +
  5019. random.nextInt(FUZZ_MILLIS);
  5020. mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
  5021. BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
  5022. mNextBackupPass = when;
  5023. }
  5024. // Report whether the backup mechanism is currently enabled
  5025. public boolean isBackupEnabled() {
  5026. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
  5027. return mEnabled; // no need to synchronize just to read it
  5028. }
  5029. // Report the name of the currently active transport
  5030. public String getCurrentTransport() {
  5031. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5032. "getCurrentTransport");
  5033. if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
  5034. return mCurrentTransport;
  5035. }
  5036. // Report all known, available backup transports
  5037. public String[] listAllTransports() {
  5038. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
  5039. String[] list = null;
  5040. ArrayList<String> known = new ArrayList<String>();
  5041. for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
  5042. if (entry.getValue() != null) {
  5043. known.add(entry.getKey());
  5044. }
  5045. }
  5046. if (known.size() > 0) {
  5047. list = new String[known.size()];
  5048. known.toArray(list);
  5049. }
  5050. return list;
  5051. }
  5052. // Select which transport to use for the next backup operation. If the given
  5053. // name is not one of the available transports, no action is taken and the method
  5054. // returns null.
  5055. public String selectBackupTransport(String transport) {
  5056. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
  5057. synchronized (mTransports) {
  5058. String prevTransport = null;
  5059. if (mTransports.get(transport) != null) {
  5060. prevTransport = mCurrentTransport;
  5061. mCurrentTransport = transport;
  5062. Settings.Secure.putString(mContext.getContentResolver(),
  5063. Settings.Secure.BACKUP_TRANSPORT, transport);
  5064. Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
  5065. + " returning " + prevTransport);
  5066. } else {
  5067. Slog.w(TAG, "Attempt to select unavailable transport " + transport);
  5068. }
  5069. return prevTransport;
  5070. }
  5071. }
  5072. // Supply the configuration Intent for the given transport. If the name is not one
  5073. // of the available transports, or if the transport does not supply any configuration
  5074. // UI, the method returns null.
  5075. public Intent getConfigurationIntent(String transportName) {
  5076. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5077. "getConfigurationIntent");
  5078. synchronized (mTransports) {
  5079. final IBackupTransport transport = mTransports.get(transportName);
  5080. if (transport != null) {
  5081. try {
  5082. final Intent intent = transport.configurationIntent();
  5083. if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
  5084. + intent);
  5085. return intent;
  5086. } catch (RemoteException e) {
  5087. /* fall through to return null */
  5088. }
  5089. }
  5090. }
  5091. return null;
  5092. }
  5093. // Supply the configuration summary string for the given transport. If the name is
  5094. // not one of the available transports, or if the transport does not supply any
  5095. // summary / destination string, the method can return null.
  5096. //
  5097. // This string is used VERBATIM as the summary text of the relevant Settings item!
  5098. public String getDestinationString(String transportName) {
  5099. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5100. "getDestinationString");
  5101. synchronized (mTransports) {
  5102. final IBackupTransport transport = mTransports.get(transportName);
  5103. if (transport != null) {
  5104. try {
  5105. final String text = transport.currentDestinationString();
  5106. if (MORE_DEBUG) Slog.d(TAG, "getDestinationString() returning " + text);
  5107. return text;
  5108. } catch (RemoteException e) {
  5109. /* fall through to return null */
  5110. }
  5111. }
  5112. }
  5113. return null;
  5114. }
  5115. // Callback: a requested backup agent has been instantiated. This should only
  5116. // be called from the Activity Manager.
  5117. public void agentConnected(String packageName, IBinder agentBinder) {
  5118. synchronized(mAgentConnectLock) {
  5119. if (Binder.getCallingUid() == Process.SYSTEM_UID) {
  5120. Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
  5121. IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
  5122. mConnectedAgent = agent;
  5123. mConnecting = false;
  5124. } else {
  5125. Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
  5126. + " claiming agent connected");
  5127. }
  5128. mAgentConnectLock.notifyAll();
  5129. }
  5130. }
  5131. // Callback: a backup agent has failed to come up, or has unexpectedly quit.
  5132. // If the agent failed to come up in the first place, the agentBinder argument
  5133. // will be null. This should only be called from the Activity Manager.
  5134. public void agentDisconnected(String packageName) {
  5135. // TODO: handle backup being interrupted
  5136. synchronized(mAgentConnectLock) {
  5137. if (Binder.getCallingUid() == Process.SYSTEM_UID) {
  5138. mConnectedAgent = null;
  5139. mConnecting = false;
  5140. } else {
  5141. Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
  5142. + " claiming agent disconnected");
  5143. }
  5144. mAgentConnectLock.notifyAll();
  5145. }
  5146. }
  5147. // An application being installed will need a restore pass, then the Package Manager
  5148. // will need to be told when the restore is finished.
  5149. public void restoreAtInstall(String packageName, int token) {
  5150. if (Binder.getCallingUid() != Process.SYSTEM_UID) {
  5151. Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
  5152. + " attemping install-time restore");
  5153. return;
  5154. }
  5155. boolean skip = false;
  5156. long restoreSet = getAvailableRestoreToken(packageName);
  5157. if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
  5158. + " token=" + Integer.toHexString(token)
  5159. + " restoreSet=" + Long.toHexString(restoreSet));
  5160. if (restoreSet == 0) {
  5161. if (MORE_DEBUG) Slog.i(TAG, "No restore set");
  5162. skip = true;
  5163. }
  5164. // Do we have a transport to fetch data for us?
  5165. IBackupTransport transport = getTransport(mCurrentTransport);
  5166. if (transport == null) {
  5167. if (DEBUG) Slog.w(TAG, "No transport");
  5168. skip = true;
  5169. }
  5170. if (!skip && mAutoRestore && mProvisioned) {
  5171. try {
  5172. // okay, we're going to attempt a restore of this package from this restore set.
  5173. // The eventual message back into the Package Manager to run the post-install
  5174. // steps for 'token' will be issued from the restore handling code.
  5175. // This can throw and so *must* happen before the wakelock is acquired
  5176. String dirName = transport.transportDirName();
  5177. // We can use a synthetic PackageInfo here because:
  5178. // 1. We know it's valid, since the Package Manager supplied the name
  5179. // 2. Only the packageName field will be used by the restore code
  5180. PackageInfo pkg = new PackageInfo();
  5181. pkg.packageName = packageName;
  5182. mWakelock.acquire();
  5183. Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
  5184. msg.obj = new RestoreParams(transport, dirName, null,
  5185. restoreSet, pkg, token, true);
  5186. mBackupHandler.sendMessage(msg);
  5187. } catch (RemoteException e) {
  5188. // Binding to the transport broke; back off and proceed with the installation.
  5189. Slog.e(TAG, "Unable to contact transport");
  5190. skip = true;
  5191. }
  5192. }
  5193. if (skip) {
  5194. // Auto-restore disabled or no way to attempt a restore; just tell the Package
  5195. // Manager to proceed with the post-install handling for this package.
  5196. if (DEBUG) Slog.v(TAG, "Skipping");
  5197. try {
  5198. mPackageManagerBinder.finishPackageInstall(token);
  5199. } catch (RemoteException e) { /* can't happen */ }
  5200. }
  5201. }
  5202. // Hand off a restore session
  5203. public IRestoreSession beginRestoreSession(String packageName, String transport) {
  5204. if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
  5205. + " transport=" + transport);
  5206. boolean needPermission = true;
  5207. if (transport == null) {
  5208. transport = mCurrentTransport;
  5209. if (packageName != null) {
  5210. PackageInfo app = null;
  5211. try {
  5212. app = mPackageManager.getPackageInfo(packageName, 0);
  5213. } catch (NameNotFoundException nnf) {
  5214. Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
  5215. throw new IllegalArgumentException("Package " + packageName + " not found");
  5216. }
  5217. if (app.applicationInfo.uid == Binder.getCallingUid()) {
  5218. // So: using the current active transport, and the caller has asked
  5219. // that its own package will be restored. In this narrow use case
  5220. // we do not require the caller to hold the permission.
  5221. needPermission = false;
  5222. }
  5223. }
  5224. }
  5225. if (needPermission) {
  5226. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5227. "beginRestoreSession");
  5228. } else {
  5229. if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed");
  5230. }
  5231. synchronized(this) {
  5232. if (mActiveRestoreSession != null) {
  5233. Slog.d(TAG, "Restore session requested but one already active");
  5234. return null;
  5235. }
  5236. mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
  5237. mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
  5238. }
  5239. return mActiveRestoreSession;
  5240. }
  5241. void clearRestoreSession(ActiveRestoreSession currentSession) {
  5242. synchronized(this) {
  5243. if (currentSession != mActiveRestoreSession) {
  5244. Slog.e(TAG, "ending non-current restore session");
  5245. } else {
  5246. if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout");
  5247. mActiveRestoreSession = null;
  5248. mBackupHandler.removeMessages(MSG_RESTORE_TIMEOUT);
  5249. }
  5250. }
  5251. }
  5252. // Note that a currently-active backup agent has notified us that it has
  5253. // completed the given outstanding asynchronous backup/restore operation.
  5254. @Override
  5255. public void opComplete(int token) {
  5256. if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
  5257. Operation op = null;
  5258. synchronized (mCurrentOpLock) {
  5259. op = mCurrentOperations.get(token);
  5260. if (op != null) {
  5261. op.state = OP_ACKNOWLEDGED;
  5262. }
  5263. mCurrentOpLock.notifyAll();
  5264. }
  5265. // The completion callback, if any, is invoked on the handler
  5266. if (op != null && op.callback != null) {
  5267. Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback);
  5268. mBackupHandler.sendMessage(msg);
  5269. }
  5270. }
  5271. // ----- Restore session -----
  5272. class ActiveRestoreSession extends IRestoreSession.Stub {
  5273. private static final String TAG = "RestoreSession";
  5274. private String mPackageName;
  5275. private IBackupTransport mRestoreTransport = null;
  5276. RestoreSet[] mRestoreSets = null;
  5277. boolean mEnded = false;
  5278. ActiveRestoreSession(String packageName, String transport) {
  5279. mPackageName = packageName;
  5280. mRestoreTransport = getTransport(transport);
  5281. }
  5282. // --- Binder interface ---
  5283. public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
  5284. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5285. "getAvailableRestoreSets");
  5286. if (observer == null) {
  5287. throw new IllegalArgumentException("Observer must not be null");
  5288. }
  5289. if (mEnded) {
  5290. throw new IllegalStateException("Restore session already ended");
  5291. }
  5292. long oldId = Binder.clearCallingIdentity();
  5293. try {
  5294. if (mRestoreTransport == null) {
  5295. Slog.w(TAG, "Null transport getting restore sets");
  5296. return -1;
  5297. }
  5298. // spin off the transport request to our service thread
  5299. mWakelock.acquire();
  5300. Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
  5301. new RestoreGetSetsParams(mRestoreTransport, this, observer));
  5302. mBackupHandler.sendMessage(msg);
  5303. return 0;
  5304. } catch (Exception e) {
  5305. Slog.e(TAG, "Error in getAvailableRestoreSets", e);
  5306. return -1;
  5307. } finally {
  5308. Binder.restoreCallingIdentity(oldId);
  5309. }
  5310. }
  5311. public synchronized int restoreAll(long token, IRestoreObserver observer) {
  5312. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5313. "performRestore");
  5314. if (DEBUG) Slog.d(TAG, "restoreAll token=" + Long.toHexString(token)
  5315. + " observer=" + observer);
  5316. if (mEnded) {
  5317. throw new IllegalStateException("Restore session already ended");
  5318. }
  5319. if (mRestoreTransport == null || mRestoreSets == null) {
  5320. Slog.e(TAG, "Ignoring restoreAll() with no restore set");
  5321. return -1;
  5322. }
  5323. if (mPackageName != null) {
  5324. Slog.e(TAG, "Ignoring restoreAll() on single-package session");
  5325. return -1;
  5326. }
  5327. String dirName;
  5328. try {
  5329. dirName = mRestoreTransport.transportDirName();
  5330. } catch (RemoteException e) {
  5331. // Transport went AWOL; fail.
  5332. Slog.e(TAG, "Unable to contact transport for restore");
  5333. return -1;
  5334. }
  5335. synchronized (mQueueLock) {
  5336. for (int i = 0; i < mRestoreSets.length; i++) {
  5337. if (token == mRestoreSets[i].token) {
  5338. long oldId = Binder.clearCallingIdentity();
  5339. mWakelock.acquire();
  5340. Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
  5341. msg.obj = new RestoreParams(mRestoreTransport, dirName,
  5342. observer, token, true);
  5343. mBackupHandler.sendMessage(msg);
  5344. Binder.restoreCallingIdentity(oldId);
  5345. return 0;
  5346. }
  5347. }
  5348. }
  5349. Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
  5350. return -1;
  5351. }
  5352. public synchronized int restoreSome(long token, IRestoreObserver observer,
  5353. String[] packages) {
  5354. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
  5355. "performRestore");
  5356. if (DEBUG) {
  5357. StringBuilder b = new StringBuilder(128);
  5358. b.append("restoreSome token=");
  5359. b.append(Long.toHexString(token));
  5360. b.append(" observer=");
  5361. b.append(observer.toString());
  5362. b.append(" packages=");
  5363. if (packages == null) {
  5364. b.append("null");
  5365. } else {
  5366. b.append('{');
  5367. boolean first = true;
  5368. for (String s : packages) {
  5369. if (!first) {
  5370. b.append(", ");
  5371. } else first = false;
  5372. b.append(s);
  5373. }
  5374. b.append('}');
  5375. }
  5376. Slog.d(TAG, b.toString());
  5377. }
  5378. if (mEnded) {
  5379. throw new IllegalStateException("Restore session already ended");
  5380. }
  5381. if (mRestoreTransport == null || mRestoreSets == null) {
  5382. Slog.e(TAG, "Ignoring restoreAll() with no restore set");
  5383. return -1;
  5384. }
  5385. if (mPackageName != null) {
  5386. Slog.e(TAG, "Ignoring restoreAll() on single-package session");
  5387. return -1;
  5388. }
  5389. String dirName;
  5390. try {
  5391. dirName = mRestoreTransport.transportDirName();
  5392. } catch (RemoteException e) {
  5393. // Transport went AWOL; fail.
  5394. Slog.e(TAG, "Unable to contact transport for restore");
  5395. return -1;
  5396. }
  5397. synchronized (mQueueLock) {
  5398. for (int i = 0; i < mRestoreSets.length; i++) {
  5399. if (token == mRestoreSets[i].token) {
  5400. long oldId = Binder.clearCallingIdentity();
  5401. mWakelock.acquire();
  5402. Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
  5403. msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
  5404. packages, true);
  5405. mBackupHandler.sendMessage(msg);
  5406. Binder.restoreCallingIdentity(oldId);
  5407. return 0;
  5408. }
  5409. }
  5410. }
  5411. Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
  5412. return -1;
  5413. }
  5414. public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
  5415. if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
  5416. if (mEnded) {
  5417. throw new IllegalStateException("Restore session already ended");
  5418. }
  5419. if (mPackageName != null) {
  5420. if (! mPackageName.equals(packageName)) {
  5421. Slog.e(TAG, "Ignoring attempt to restore pkg=" + packageName
  5422. + " on session for package " + mPackageName);
  5423. return -1;
  5424. }
  5425. }
  5426. PackageInfo app = null;
  5427. try {
  5428. app = mPackageManager.getPackageInfo(packageName, 0);
  5429. } catch (NameNotFoundException nnf) {
  5430. Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
  5431. return -1;
  5432. }
  5433. // If the caller is not privileged and is not coming from the target
  5434. // app's uid, throw a permission exception back to the caller.
  5435. int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
  5436. Binder.getCallingPid(), Binder.getCallingUid());
  5437. if ((perm == PackageManager.PERMISSION_DENIED) &&
  5438. (app.applicationInfo.uid != Binder.getCallingUid())) {
  5439. Slog.w(TAG, "restorePackage: bad packageName=" + packageName
  5440. + " or calling uid=" + Binder.getCallingUid());
  5441. throw new SecurityException("No permission to restore other packages");
  5442. }
  5443. // If the package has no backup agent, we obviously cannot proceed
  5444. if (app.applicationInfo.backupAgentName == null) {
  5445. Slog.w(TAG, "Asked to restore package " + packageName + " with no agent");
  5446. return -1;
  5447. }
  5448. // So far so good; we're allowed to try to restore this package. Now
  5449. // check whether there is data for it in the current dataset, falling back
  5450. // to the ancestral dataset if not.
  5451. long token = getAvailableRestoreToken(packageName);
  5452. // If we didn't come up with a place to look -- no ancestral dataset and
  5453. // the app has never been backed up from this device -- there's nothing
  5454. // to do but return failure.
  5455. if (token == 0) {
  5456. if (DEBUG) Slog.w(TAG, "No data available for this package; not restoring");
  5457. return -1;
  5458. }
  5459. String dirName;
  5460. try {
  5461. dirName = mRestoreTransport.transportDirName();
  5462. } catch (RemoteException e) {
  5463. // Transport went AWOL; fail.
  5464. Slog.e(TAG, "Unable to contact transport for restore");
  5465. return -1;
  5466. }
  5467. // Ready to go: enqueue the restore request and claim success
  5468. long oldId = Binder.clearCallingIdentity();
  5469. mWakelock.acquire();
  5470. Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
  5471. msg.obj = new RestoreParams(mRestoreTransport, dirName,
  5472. observer, token, app, 0, false);
  5473. mBackupHandler.sendMessage(msg);
  5474. Binder.restoreCallingIdentity(oldId);
  5475. return 0;
  5476. }
  5477. // Posted to the handler to tear down a restore session in a cleanly synchronized way
  5478. class EndRestoreRunnable implements Runnable {
  5479. BackupManagerService mBackupManager;
  5480. ActiveRestoreSession mSession;
  5481. EndRestoreRunnable(BackupManagerService manager, ActiveRestoreSession session) {
  5482. mBackupManager = manager;
  5483. mSession = session;
  5484. }
  5485. public void run() {
  5486. // clean up the session's bookkeeping
  5487. synchronized (mSession) {
  5488. try {
  5489. if (mSession.mRestoreTransport != null) {
  5490. mSession.mRestoreTransport.finishRestore();
  5491. }
  5492. } catch (Exception e) {
  5493. Slog.e(TAG, "Error in finishRestore", e);
  5494. } finally {
  5495. mSession.mRestoreTransport = null;
  5496. mSession.mEnded = true;
  5497. }
  5498. }
  5499. // clean up the BackupManagerService side of the bookkeeping
  5500. // and cancel any pending timeout message
  5501. mBackupManager.clearRestoreSession(mSession);
  5502. }
  5503. }
  5504. public synchronized void endRestoreSession() {
  5505. if (DEBUG) Slog.d(TAG, "endRestoreSession");
  5506. if (mEnded) {
  5507. throw new IllegalStateException("Restore session already ended");
  5508. }
  5509. mBackupHandler.post(new EndRestoreRunnable(BackupManagerService.this, this));
  5510. }
  5511. }
  5512. @Override
  5513. public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  5514. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
  5515. long identityToken = Binder.clearCallingIdentity();
  5516. try {
  5517. dumpInternal(pw);
  5518. } finally {
  5519. Binder.restoreCallingIdentity(identityToken);
  5520. }
  5521. }
  5522. private void dumpInternal(PrintWriter pw) {
  5523. synchronized (mQueueLock) {
  5524. pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
  5525. + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
  5526. + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
  5527. pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
  5528. if (mBackupRunning) pw.println("Backup currently running");
  5529. pw.println("Last backup pass started: " + mLastBackupPass
  5530. + " (now = " + System.currentTimeMillis() + ')');
  5531. pw.println(" next scheduled: " + mNextBackupPass);
  5532. pw.println("Available transports:");
  5533. for (String t : listAllTransports()) {
  5534. pw.println((t.equals(mCurrentTransport) ? " * " : " ") + t);
  5535. try {
  5536. IBackupTransport transport = getTransport(t);
  5537. File dir = new File(mBaseStateDir, transport.transportDirName());
  5538. pw.println(" destination: " + transport.currentDestinationString());
  5539. pw.println(" intent: " + transport.configurationIntent());
  5540. for (File f : dir.listFiles()) {
  5541. pw.println(" " + f.getName() + " - " + f.length() + " state bytes");
  5542. }
  5543. } catch (Exception e) {
  5544. Slog.e(TAG, "Error in transport", e);
  5545. pw.println(" Error: " + e);
  5546. }
  5547. }
  5548. pw.println("Pending init: " + mPendingInits.size());
  5549. for (String s : mPendingInits) {
  5550. pw.println(" " + s);
  5551. }
  5552. if (DEBUG_BACKUP_TRACE) {
  5553. synchronized (mBackupTrace) {
  5554. if (!mBackupTrace.isEmpty()) {
  5555. pw.println("Most recent backup trace:");
  5556. for (String s : mBackupTrace) {
  5557. pw.println(" " + s);
  5558. }
  5559. }
  5560. }
  5561. }
  5562. int N = mBackupParticipants.size();
  5563. pw.println("Participants:");
  5564. for (int i=0; i<N; i++) {
  5565. int uid = mBackupParticipants.keyAt(i);
  5566. pw.print(" uid: ");
  5567. pw.println(uid);
  5568. HashSet<String> participants = mBackupParticipants.valueAt(i);
  5569. for (String app: participants) {
  5570. pw.println(" " + app);
  5571. }
  5572. }
  5573. pw.println("Ancestral packages: "
  5574. + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
  5575. if (mAncestralPackages != null) {
  5576. for (String pkg : mAncestralPackages) {
  5577. pw.println(" " + pkg);
  5578. }
  5579. }
  5580. pw.println("Ever backed up: " + mEverStoredApps.size());
  5581. for (String pkg : mEverStoredApps) {
  5582. pw.println(" " + pkg);
  5583. }
  5584. pw.println("Pending backup: " + mPendingBackups.size());
  5585. for (BackupRequest req : mPendingBackups.values()) {
  5586. pw.println(" " + req);
  5587. }
  5588. }
  5589. }
  5590. }