blob: 0f8ccd7bc403e6efd3931a83bf5c7c5c454cc1b1 [file] [log] [blame]
Christopher Tate46cc43c2013-02-19 14:08:59 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.sharedstoragebackup;
18
19import android.app.Service;
Christopher Tate46cc43c2013-02-19 14:08:59 -080020import android.app.backup.FullBackup;
Christopher Tate11ae7682015-03-24 18:48:10 -070021import android.app.backup.FullBackupDataOutput;
Christopher Tate46cc43c2013-02-19 14:08:59 -080022import android.app.backup.IBackupManager;
23import android.content.Intent;
24import android.os.Environment;
25import android.os.IBinder;
26import android.os.ParcelFileDescriptor;
27import android.os.RemoteException;
28import android.util.Log;
29
30import java.io.File;
31import java.io.FileDescriptor;
32import java.io.FileOutputStream;
33import java.io.IOException;
34import java.util.ArrayList;
35
36import com.android.internal.backup.IObbBackupService;
37
38/**
39 * Service that the Backup Manager Services delegates OBB backup/restore operations to,
40 * because those require accessing external storage.
41 *
42 * {@hide}
43 */
44public class ObbBackupService extends Service {
45 static final String TAG = "ObbBackupService";
46 static final boolean DEBUG = true;
47
48 /**
49 * IObbBackupService interface implementation
50 */
51 IObbBackupService mService = new IObbBackupService.Stub() {
52 /*
53 * Back up a package's OBB directory tree
54 */
55 @Override
56 public void backupObbs(String packageName, ParcelFileDescriptor data,
57 int token, IBackupManager callbackBinder) {
58 final FileDescriptor outFd = data.getFileDescriptor();
59 try {
Jeff Sharkey7f392de2013-08-11 17:42:17 -070060 File obbDir = Environment.buildExternalStorageAppObbDirs(packageName)[0];
Christopher Tate46cc43c2013-02-19 14:08:59 -080061 if (obbDir != null) {
62 if (obbDir.exists()) {
63 ArrayList<File> obbList = allFileContents(obbDir);
64 if (obbList != null) {
65 // okay, there's at least something there
66 if (DEBUG) {
67 Log.i(TAG, obbList.size() + " files to back up");
68 }
69 final String rootPath = obbDir.getCanonicalPath();
Christopher Tate11ae7682015-03-24 18:48:10 -070070 final FullBackupDataOutput out = new FullBackupDataOutput(data);
Christopher Tate46cc43c2013-02-19 14:08:59 -080071 for (File f : obbList) {
72 final String filePath = f.getCanonicalPath();
73 if (DEBUG) {
74 Log.i(TAG, "storing: " + filePath);
75 }
76 FullBackup.backupToTar(packageName, FullBackup.OBB_TREE_TOKEN, null,
77 rootPath, filePath, out);
78 }
79 }
80 }
81 }
82 } catch (IOException e) {
83 Log.w(TAG, "Exception backing up OBBs for " + packageName, e);
84 } finally {
85 // Send the EOD marker indicating that there is no more data
86 try {
87 FileOutputStream out = new FileOutputStream(outFd);
88 byte[] buf = new byte[4];
89 out.write(buf);
90 } catch (IOException e) {
91 Log.e(TAG, "Unable to finalize obb backup stream!");
92 }
93
94 try {
Christopher Tate11ae7682015-03-24 18:48:10 -070095 callbackBinder.opComplete(token, 0);
Christopher Tate46cc43c2013-02-19 14:08:59 -080096 } catch (RemoteException e) {
97 }
98 }
99 }
100
101 /*
102 * Restore an OBB file for the given package from the incoming stream
103 */
104 @Override
105 public void restoreObbFile(String packageName, ParcelFileDescriptor data,
106 long fileSize, int type, String path, long mode, long mtime,
107 int token, IBackupManager callbackBinder) {
108 try {
Jeff Sharkey7f392de2013-08-11 17:42:17 -0700109 File outFile = Environment.buildExternalStorageAppObbDirs(packageName)[0];
Christopher Tate46cc43c2013-02-19 14:08:59 -0800110 if (outFile != null) {
111 outFile = new File(outFile, path);
112 }
113 // outFile is null here if we couldn't get access to external storage,
114 // in which case restoreFile() will discard the data cleanly and let
115 // us proceed with the next file segment in the stream. We pass -1
116 // for the file mode to suppress attempts to chmod() on shared storage.
117 FullBackup.restoreFile(data, fileSize, type, -1, mtime, outFile);
118 } catch (IOException e) {
119 Log.i(TAG, "Exception restoring OBB " + path, e);
120 } finally {
121 try {
Christopher Tate11ae7682015-03-24 18:48:10 -0700122 callbackBinder.opComplete(token, 0);
Christopher Tate46cc43c2013-02-19 14:08:59 -0800123 } catch (RemoteException e) {
124 }
125 }
126 }
127
128 ArrayList<File> allFileContents(File rootDir) {
129 final ArrayList<File> files = new ArrayList<File>();
130 final ArrayList<File> dirs = new ArrayList<File>();
131
132 dirs.add(rootDir);
133 while (!dirs.isEmpty()) {
134 File dir = dirs.remove(0);
135 File[] contents = dir.listFiles();
136 if (contents != null) {
137 for (File f : contents) {
138 if (f.isDirectory()) dirs.add(f);
139 else if (f.isFile()) files.add(f);
140 }
141 }
142 }
143 return files;
144 }
145 };
146
147 @Override
148 public IBinder onBind(Intent intent) {
149 return mService.asBinder();
150 }
151}