Home | History | Annotate | Download | only in backup
      1 package com.android.server.backup;
      2 
      3 import static android.os.ParcelFileDescriptor.MODE_CREATE;
      4 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
      5 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
      6 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
      7 
      8 import android.app.IBackupAgent;
      9 import android.app.backup.BackupDataInput;
     10 import android.app.backup.BackupDataOutput;
     11 import android.app.backup.FullBackup;
     12 import android.os.ParcelFileDescriptor;
     13 import android.os.RemoteException;
     14 import android.util.Slog;
     15 
     16 import com.android.server.backup.restore.PerformAdbRestoreTask;
     17 
     18 import libcore.io.IoUtils;
     19 
     20 import java.io.File;
     21 import java.io.FileInputStream;
     22 import java.io.FileOutputStream;
     23 import java.io.IOException;
     24 import java.util.ArrayList;
     25 import java.util.Collections;
     26 import java.util.HashMap;
     27 import java.util.List;
     28 import java.util.Map;
     29 
     30 /**
     31  * Used by BackupManagerService to perform adb restore for key-value packages. At the moment this
     32  * class resembles what is done in the standard key-value code paths in BackupManagerService, and
     33  * should be unified later.
     34  *
     35  * TODO: We should create unified backup/restore engines that can be used for both transport and
     36  * adb backup/restore, and for fullbackup and key-value backup.
     37  */
     38 public class KeyValueAdbRestoreEngine implements Runnable {
     39     private static final String TAG = "KeyValueAdbRestoreEngine";
     40     private static final boolean DEBUG = false;
     41 
     42     private final BackupManagerServiceInterface mBackupManagerService;
     43     private final File mDataDir;
     44 
     45     FileMetadata mInfo;
     46     PerformAdbRestoreTask mRestoreTask;
     47     ParcelFileDescriptor mInFD;
     48     IBackupAgent mAgent;
     49     int mToken;
     50 
     51     public KeyValueAdbRestoreEngine(BackupManagerServiceInterface backupManagerService,
     52             File dataDir, FileMetadata info, ParcelFileDescriptor inFD, IBackupAgent agent,
     53             int token) {
     54         mBackupManagerService = backupManagerService;
     55         mDataDir = dataDir;
     56         mInfo = info;
     57         mInFD = inFD;
     58         mAgent = agent;
     59         mToken = token;
     60     }
     61 
     62     @Override
     63     public void run() {
     64         try {
     65             File restoreData = prepareRestoreData(mInfo, mInFD);
     66 
     67             invokeAgentForAdbRestore(mAgent, mInfo, restoreData);
     68         } catch (IOException e) {
     69             e.printStackTrace();
     70         }
     71     }
     72 
     73     private File prepareRestoreData(FileMetadata info, ParcelFileDescriptor inFD) throws IOException {
     74         String pkg = info.packageName;
     75         File restoreDataName = new File(mDataDir, pkg + ".restore");
     76         File sortedDataName = new File(mDataDir, pkg + ".sorted");
     77 
     78         FullBackup.restoreFile(inFD, info.size, info.type, info.mode, info.mtime, restoreDataName);
     79 
     80         // Sort the keys, as the BackupAgent expect them to come in lexicographical order
     81         sortKeyValueData(restoreDataName, sortedDataName);
     82         return sortedDataName;
     83     }
     84 
     85     private void invokeAgentForAdbRestore(IBackupAgent agent, FileMetadata info, File restoreData)
     86             throws IOException {
     87         String pkg = info.packageName;
     88         File newStateName = new File(mDataDir, pkg + ".new");
     89         try {
     90             ParcelFileDescriptor backupData =
     91                     ParcelFileDescriptor.open(restoreData, MODE_READ_ONLY);
     92             ParcelFileDescriptor newState = ParcelFileDescriptor.open(newStateName,
     93                     MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
     94 
     95             if (DEBUG) {
     96                 Slog.i(TAG, "Starting restore of package " + pkg + " for version code "
     97                         + info.version);
     98             }
     99             agent.doRestore(backupData, info.version, newState, mToken,
    100                     mBackupManagerService.getBackupManagerBinder());
    101         } catch (IOException e) {
    102             Slog.e(TAG, "Exception opening file. " + e);
    103         } catch (RemoteException e) {
    104             Slog.e(TAG, "Exception calling doRestore on agent: " + e);
    105         }
    106     }
    107 
    108     private void sortKeyValueData (File restoreData, File sortedData) throws IOException {
    109         FileInputStream inputStream = null;
    110         FileOutputStream outputStream = null;
    111         try {
    112             inputStream = new FileInputStream(restoreData);
    113             outputStream = new FileOutputStream(sortedData);
    114             BackupDataInput reader = new BackupDataInput(inputStream.getFD());
    115             BackupDataOutput writer = new BackupDataOutput(outputStream.getFD());
    116             copyKeysInLexicalOrder(reader, writer);
    117         } finally {
    118             if (inputStream != null) {
    119                 IoUtils.closeQuietly(inputStream);
    120             }
    121             if (outputStream != null) {
    122                 IoUtils.closeQuietly(outputStream);
    123             }
    124         }
    125     }
    126 
    127     private void copyKeysInLexicalOrder(BackupDataInput in, BackupDataOutput out)
    128             throws IOException {
    129         Map<String, byte[]> data = new HashMap<>();
    130         while (in.readNextHeader()) {
    131             String key = in.getKey();
    132             int size = in.getDataSize();
    133             if (size < 0) {
    134                 in.skipEntityData();
    135                 continue;
    136             }
    137             byte[] value = new byte[size];
    138             in.readEntityData(value, 0, size);
    139             data.put(key, value);
    140         }
    141         List<String> keys = new ArrayList<>(data.keySet());
    142         Collections.sort(keys);
    143         for (String key : keys) {
    144             byte[] value = data.get(key);
    145             out.writeEntityHeader(key, value.length);
    146             out.writeEntityData(value, value.length);
    147         }
    148     }
    149 }
    150