summaryrefslogtreecommitdiffstats
path: root/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
blob: 6c677b8785019399a53e96e9f10b398188299c03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.android.sharedstoragebackup;

import android.app.backup.FullBackupAgent;
import android.app.backup.FullBackup;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackupDataOutput;
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.util.Slog;

import java.io.File;
import java.io.IOException;

public class SharedStorageAgent extends FullBackupAgent {
    static final String TAG = "SharedStorageAgent";
    static final boolean DEBUG = true;

    StorageVolume[] mVolumes;

    @Override
    public void onCreate() {
        StorageManager mgr = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
        if (mgr != null) {
            mVolumes = mgr.getVolumeList();
        } else {
            Slog.e(TAG, "Unable to access Storage Manager");
        }
    }

    /**
     * Full backup of the shared-storage filesystem
     */
    @Override
    public void onFullBackup(FullBackupDataOutput output) throws IOException {
        // If there are shared-storage volumes available, run the inherited directory-
        // hierarchy backup process on them.  By convention in the Storage Manager, the
        // "primary" shared storage volume is first in the list.
        if (mVolumes != null) {
            for (int i = 0; i < mVolumes.length; i++) {
                StorageVolume v = mVolumes[i];
                // Express the contents of volume N this way in the tar stream:
                //     shared/N/path/to/file
                // The restore will then extract to the given volume
                String domain = FullBackup.SHARED_PREFIX + i;
                fullBackupFileTree(null, domain, v.getPath(), null, output);
            }
        }
    }

    /**
     * Full restore of one file to shared storage
     */
    @Override
    public void onRestoreFile(ParcelFileDescriptor data, long size,
            int type, String domain, String relpath, long mode, long mtime)
            throws IOException {
        Slog.d(TAG, "Shared restore: [ " + domain + " : " + relpath + "]");

        File outFile = null;

        // The file path must be in the semantic form [number]/path/to/file...
        int slash = relpath.indexOf('/');
        if (slash > 0) {
            try {
                int i = Integer.parseInt(relpath.substring(0, slash));
                if (i <= mVolumes.length) {
                    outFile = new File(mVolumes[i].getPath(), relpath.substring(slash + 1));
                    if (DEBUG) Slog.i(TAG, " => " + outFile.getAbsolutePath());
                } else {
                    Slog.w(TAG, "Cannot restore data for unavailable volume " + i);
                }
            } catch (NumberFormatException e) {
                if (DEBUG) Slog.w(TAG, "Bad volume number token: " + relpath.substring(0, slash));
            }
        } else {
            if (DEBUG) Slog.i(TAG, "Can't find volume-number token");
        }
        if (outFile == null) {
            Slog.e(TAG, "Skipping data with malformed path " + relpath);
        }

        FullBackup.restoreFile(data, size, type, -1, mtime, outFile);
    }
}