diff options
author | Christopher Tate <ctate@google.com> | 2013-02-19 14:08:59 -0800 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2013-03-07 13:47:20 -0800 |
commit | 46cc43c6fa7623820d4ae9149496cf96bb15f8a3 (patch) | |
tree | fe3a33bcdf0dc82414eb274aedefaef53aace059 /packages/SharedStorageBackup | |
parent | 32884c376fd06799f46ea3b1ded89ba9d21f8f14 (diff) | |
download | frameworks_base-46cc43c6fa7623820d4ae9149496cf96bb15f8a3.zip frameworks_base-46cc43c6fa7623820d4ae9149496cf96bb15f8a3.tar.gz frameworks_base-46cc43c6fa7623820d4ae9149496cf96bb15f8a3.tar.bz2 |
Full backup/restore now handles OBBs sensibly
OBB backup/ restore is no longer handled within the target app
process. This is done to avoid having to require that OBB-using
apps have full read/write permission for external storage.
The new OBB backup service is a new component running in the
same app as the already-existing shared storage backup agent.
The backup infrastructure delegates backup/restore of apps'
OBB contents to this component (because the system process
may not itself read/write external storage).
From the command line, OBB backup is enabled by using new
-obb / -noobb flags with adb backup. The default is noobb.
Finally, a couple of nit fixes:
- buffer-size mismatch between the writer and reader of chunked
file data has been corrected; now the reading side won't be
issuing an extra pipe read per chunk.
- bu now explicitly closes the transport socket fd after
adopting it. This was benign but triggered a logged
warning about leaked fds.
Bug: 6718844
Change-Id: Ie252494e2327e9ab97cf9ed87c298410a8618492
Diffstat (limited to 'packages/SharedStorageBackup')
3 files changed, 159 insertions, 0 deletions
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml index fc21df3..b8df88e 100644 --- a/packages/SharedStorageBackup/AndroidManifest.xml +++ b/packages/SharedStorageBackup/AndroidManifest.xml @@ -24,5 +24,12 @@ <application android:allowClearUserData="false" android:permission="android.permission.CONFIRM_FULL_BACKUP" android:backupAgent="SharedStorageAgent" > + + <service android:name=".ObbBackupService" + android:enabled="true" + android:exported="true"> + </service> + </application> + </manifest> diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags index f43cb81..6a66a47 100644 --- a/packages/SharedStorageBackup/proguard.flags +++ b/packages/SharedStorageBackup/proguard.flags @@ -1 +1,2 @@ -keep class com.android.sharedstoragebackup.SharedStorageAgent +-keep class com.android.sharedstoragebackup.ObbBackupService diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java new file mode 100644 index 0000000..7ebe096 --- /dev/null +++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sharedstoragebackup; + +import android.app.Service; +import android.app.backup.BackupDataOutput; +import android.app.backup.FullBackup; +import android.app.backup.IBackupManager; +import android.content.Intent; +import android.os.Environment; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Log; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; + +import com.android.internal.backup.IObbBackupService; + +/** + * Service that the Backup Manager Services delegates OBB backup/restore operations to, + * because those require accessing external storage. + * + * {@hide} + */ +public class ObbBackupService extends Service { + static final String TAG = "ObbBackupService"; + static final boolean DEBUG = true; + + /** + * IObbBackupService interface implementation + */ + IObbBackupService mService = new IObbBackupService.Stub() { + /* + * Back up a package's OBB directory tree + */ + @Override + public void backupObbs(String packageName, ParcelFileDescriptor data, + int token, IBackupManager callbackBinder) { + final FileDescriptor outFd = data.getFileDescriptor(); + try { + File obbDir = Environment.getExternalStorageAppObbDirectory(packageName); + if (obbDir != null) { + if (obbDir.exists()) { + ArrayList<File> obbList = allFileContents(obbDir); + if (obbList != null) { + // okay, there's at least something there + if (DEBUG) { + Log.i(TAG, obbList.size() + " files to back up"); + } + final String rootPath = obbDir.getCanonicalPath(); + final BackupDataOutput out = new BackupDataOutput(outFd); + for (File f : obbList) { + final String filePath = f.getCanonicalPath(); + if (DEBUG) { + Log.i(TAG, "storing: " + filePath); + } + FullBackup.backupToTar(packageName, FullBackup.OBB_TREE_TOKEN, null, + rootPath, filePath, out); + } + } + } + } + } catch (IOException e) { + Log.w(TAG, "Exception backing up OBBs for " + packageName, e); + } finally { + // Send the EOD marker indicating that there is no more data + try { + FileOutputStream out = new FileOutputStream(outFd); + byte[] buf = new byte[4]; + out.write(buf); + } catch (IOException e) { + Log.e(TAG, "Unable to finalize obb backup stream!"); + } + + try { + callbackBinder.opComplete(token); + } catch (RemoteException e) { + } + } + } + + /* + * Restore an OBB file for the given package from the incoming stream + */ + @Override + public void restoreObbFile(String packageName, ParcelFileDescriptor data, + long fileSize, int type, String path, long mode, long mtime, + int token, IBackupManager callbackBinder) { + try { + File outFile = Environment.getExternalStorageAppObbDirectory(packageName); + if (outFile != null) { + outFile = new File(outFile, path); + } + // outFile is null here if we couldn't get access to external storage, + // in which case restoreFile() will discard the data cleanly and let + // us proceed with the next file segment in the stream. We pass -1 + // for the file mode to suppress attempts to chmod() on shared storage. + FullBackup.restoreFile(data, fileSize, type, -1, mtime, outFile); + } catch (IOException e) { + Log.i(TAG, "Exception restoring OBB " + path, e); + } finally { + try { + callbackBinder.opComplete(token); + } catch (RemoteException e) { + } + } + } + + ArrayList<File> allFileContents(File rootDir) { + final ArrayList<File> files = new ArrayList<File>(); + final ArrayList<File> dirs = new ArrayList<File>(); + + dirs.add(rootDir); + while (!dirs.isEmpty()) { + File dir = dirs.remove(0); + File[] contents = dir.listFiles(); + if (contents != null) { + for (File f : contents) { + if (f.isDirectory()) dirs.add(f); + else if (f.isFile()) files.add(f); + } + } + } + return files; + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mService.asBinder(); + } +} |