1 /*
2  * Copyright (C) 2011 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 
17 package com.android.commands.bu;
18 
19 import android.annotation.UserIdInt;
20 import android.app.backup.IBackupManager;
21 import android.os.ParcelFileDescriptor;
22 import android.os.RemoteException;
23 import android.os.ServiceManager;
24 import android.os.UserHandle;
25 import android.system.OsConstants;
26 import android.util.Log;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 
30 import java.io.IOException;
31 import java.util.ArrayList;
32 
33 public final class Backup {
34     static final String TAG = "bu";
35 
36     static String[] mArgs;
37     int mNextArg;
38     IBackupManager mBackupManager;
39 
40     @VisibleForTesting
Backup(IBackupManager backupManager)41     Backup(IBackupManager backupManager) {
42         mBackupManager = backupManager;
43     }
44 
Backup()45     Backup() {
46         mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
47     }
48 
main(String[] args)49     public static void main(String[] args) {
50         try {
51             new Backup().run(args);
52         } catch (Exception e) {
53             Log.e(TAG, "Error running backup/restore", e);
54         }
55         Log.d(TAG, "Finished.");
56     }
57 
run(String[] args)58     public void run(String[] args) {
59         if (mBackupManager == null) {
60             Log.e(TAG, "Can't obtain Backup Manager binder");
61             return;
62         }
63 
64         Log.d(TAG, "Beginning: " + args[0]);
65         mArgs = args;
66 
67         int userId = parseUserId();
68         if (!isBackupActiveForUser(userId)) {
69             Log.e(TAG, "BackupManager is not available for user " + userId);
70             return;
71         }
72 
73         String arg = nextArg();
74         if (arg.equals("backup")) {
75             doBackup(OsConstants.STDOUT_FILENO, userId);
76         } else if (arg.equals("restore")) {
77             doRestore(OsConstants.STDIN_FILENO, userId);
78         } else {
79             showUsage();
80         }
81     }
82 
doBackup(int socketFd, @UserIdInt int userId)83     private void doBackup(int socketFd, @UserIdInt int userId) {
84         ArrayList<String> packages = new ArrayList<String>();
85         boolean saveApks = false;
86         boolean saveObbs = false;
87         boolean saveShared = false;
88         boolean doEverything = false;
89         boolean doWidgets = false;
90         boolean allIncludesSystem = true;
91         boolean doCompress = true;
92         boolean doKeyValue = false;
93 
94         String arg;
95         while ((arg = nextArg()) != null) {
96             if (arg.startsWith("-")) {
97                 if ("-apk".equals(arg)) {
98                     saveApks = true;
99                 } else if ("-noapk".equals(arg)) {
100                     saveApks = false;
101                 } else if ("-obb".equals(arg)) {
102                     saveObbs = true;
103                 } else if ("-noobb".equals(arg)) {
104                     saveObbs = false;
105                 } else if ("-shared".equals(arg)) {
106                     saveShared = true;
107                 } else if ("-noshared".equals(arg)) {
108                     saveShared = false;
109                 } else if ("-system".equals(arg)) {
110                     allIncludesSystem = true;
111                 } else if ("-nosystem".equals(arg)) {
112                     allIncludesSystem = false;
113                 } else if ("-widgets".equals(arg)) {
114                     doWidgets = true;
115                 } else if ("-nowidgets".equals(arg)) {
116                     doWidgets = false;
117                 } else if ("-all".equals(arg)) {
118                     doEverything = true;
119                 } else if ("-compress".equals(arg)) {
120                     doCompress = true;
121                 } else if ("-nocompress".equals(arg)) {
122                     doCompress = false;
123                 } else if ("-keyvalue".equals(arg)) {
124                     doKeyValue = true;
125                 } else if ("-nokeyvalue".equals(arg)) {
126                     doKeyValue = false;
127                 } else if ("-user".equals(arg)) {
128                     // User ID has been processed in run(), ignore the next argument.
129                     nextArg();
130                     continue;
131                 } else {
132                     Log.w(TAG, "Unknown backup flag " + arg);
133                     continue;
134                 }
135             } else {
136                 // Not a flag; treat as a package name
137                 packages.add(arg);
138             }
139         }
140 
141         if (doEverything && packages.size() > 0) {
142             Log.w(TAG, "-all passed for backup along with specific package names");
143         }
144 
145         if (!doEverything && !saveShared && packages.size() == 0) {
146             Log.e(TAG, "no backup packages supplied and neither -shared nor -all given");
147             return;
148         }
149 
150         ParcelFileDescriptor fd = null;
151         try {
152             fd = ParcelFileDescriptor.adoptFd(socketFd);
153             String[] packArray = new String[packages.size()];
154             mBackupManager.adbBackup(userId, fd, saveApks, saveObbs, saveShared, doWidgets, doEverything,
155                     allIncludesSystem, doCompress, doKeyValue, packages.toArray(packArray));
156         } catch (RemoteException e) {
157             Log.e(TAG, "Unable to invoke backup manager for backup");
158         } finally {
159             if (fd != null) {
160                 try {
161                     fd.close();
162                 } catch (IOException e) {
163                     Log.e(TAG, "IO error closing output for backup: " + e.getMessage());
164                 }
165             }
166         }
167     }
168 
doRestore(int socketFd, @UserIdInt int userId)169     private void doRestore(int socketFd, @UserIdInt int userId) {
170         // No arguments to restore
171         ParcelFileDescriptor fd = null;
172         try {
173             fd = ParcelFileDescriptor.adoptFd(socketFd);
174             mBackupManager.adbRestore(userId, fd);
175         } catch (RemoteException e) {
176             Log.e(TAG, "Unable to invoke backup manager for restore");
177         } finally {
178             if (fd != null) {
179                 try {
180                     fd.close();
181                 } catch (IOException e) {}
182             }
183         }
184     }
185 
parseUserId()186     private @UserIdInt int parseUserId() {
187         for (int argNumber = 0; argNumber < mArgs.length - 1; argNumber++) {
188             if ("-user".equals(mArgs[argNumber])) {
189                 return UserHandle.parseUserArg(mArgs[argNumber + 1]);
190             }
191         }
192 
193         return UserHandle.USER_SYSTEM;
194     }
195 
isBackupActiveForUser(int userId)196     private boolean isBackupActiveForUser(int userId) {
197         try {
198             return mBackupManager.isBackupServiceActive(userId);
199         } catch (RemoteException e) {
200             Log.e(TAG, "Could not access BackupManager: " + e.toString());
201             return false;
202         }
203     }
204 
showUsage()205     private static void showUsage() {
206         System.err.println(" backup [-user USER_ID] [-f FILE] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared]");
207         System.err.println("        [-all] [-system|-nosystem] [-keyvalue|-nokeyvalue] [PACKAGE...]");
208         System.err.println("     write an archive of the device's data to FILE [default=backup.adb]");
209         System.err.println("     package list optional if -all/-shared are supplied");
210         System.err.println("     -user: user ID for which to perform the operation (default - system user)");
211         System.err.println("     -apk/-noapk: do/don't back up .apk files (default -noapk)");
212         System.err.println("     -obb/-noobb: do/don't back up .obb files (default -noobb)");
213         System.err.println("     -shared|-noshared: do/don't back up shared storage (default -noshared)");
214         System.err.println("     -all: back up all installed applications");
215         System.err.println("     -system|-nosystem: include system apps in -all (default -system)");
216         System.err.println("     -keyvalue|-nokeyvalue: include apps that perform key/value backups.");
217         System.err.println("         (default -nokeyvalue)");
218         System.err.println(" restore [-user USER_ID] FILE       restore device contents from FILE");
219         System.err.println("     -user: user ID for which to perform the operation (default - system user)");
220     }
221 
nextArg()222     private String nextArg() {
223         if (mNextArg >= mArgs.length) {
224             return null;
225         }
226         String arg = mArgs[mNextArg];
227         mNextArg++;
228         return arg;
229     }
230 }