summaryrefslogtreecommitdiffstats
path: root/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java')
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java305
1 files changed, 305 insertions, 0 deletions
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
new file mode 100644
index 0000000..d36207b
--- /dev/null
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -0,0 +1,305 @@
+package com.android.defcontainer;
+
+import com.android.internal.app.IMediaContainerService;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.IMountService;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.app.Service;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.os.FileUtils;
+
+
+/*
+ * This service copies a downloaded apk to a file passed in as
+ * a ParcelFileDescriptor or to a newly created container specified
+ * by parameters. The DownloadManager gives access to this process
+ * based on its uid. This process also needs the ACCESS_DOWNLOAD_MANAGER
+ * permission to access apks downloaded via the download manager.
+ */
+public class DefaultContainerService extends Service {
+ private static final String TAG = "DefContainer";
+ private static final boolean localLOGV = false;
+
+ private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
+ /*
+ * Creates a new container and copies resource there.
+ * @param paackageURI the uri of resource to be copied. Can be either
+ * a content uri or a file uri
+ * @param containerId the id of the secure container that should
+ * be used for creating a secure container into which the resource
+ * will be copied.
+ * @param key Refers to key used for encrypting the secure container
+ * @param resFileName Name of the target resource file(relative to newly
+ * created secure container)
+ * @return Returns the new cache path where the resource has been copied into
+ *
+ */
+ public String copyResourceToContainer(final Uri packageURI,
+ final String containerId,
+ final String key, final String resFileName) {
+ if (packageURI == null || containerId == null) {
+ return null;
+ }
+ return copyResourceInner(packageURI, containerId, key, resFileName);
+ }
+
+ /*
+ * Copy specified resource to output stream
+ * @param packageURI the uri of resource to be copied. Should be a
+ * file uri
+ * @param outStream Remote file descriptor to be used for copying
+ * @return Returns true if copy succeded or false otherwise.
+ */
+ public boolean copyResource(final Uri packageURI,
+ ParcelFileDescriptor outStream) {
+ if (packageURI == null || outStream == null) {
+ return false;
+ }
+ ParcelFileDescriptor.AutoCloseOutputStream
+ autoOut = new ParcelFileDescriptor.AutoCloseOutputStream(outStream);
+ return copyFile(packageURI, autoOut);
+ }
+ };
+
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ private IMountService getMountService() {
+ return IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+ }
+
+ private String copyResourceInner(Uri packageURI, String newCacheId, String key, String resFileName) {
+ // Create new container at newCachePath
+ String codePath = packageURI.getPath();
+ String newCachePath = null;
+ final int CREATE_FAILED = 1;
+ final int COPY_FAILED = 2;
+ final int FINALIZE_FAILED = 3;
+ final int PASS = 4;
+ int errCode = CREATE_FAILED;
+ // Create new container
+ if ((newCachePath = createSdDir(packageURI, newCacheId, key)) != null) {
+ File resFile = new File(newCachePath, resFileName);
+ errCode = COPY_FAILED;
+ if (localLOGV) Log.i(TAG, "Trying to copy " + codePath + " to " + resFile);
+ // Copy file from codePath
+ if (FileUtils.copyFile(new File(codePath), resFile)) {
+ errCode = FINALIZE_FAILED;
+ if (finalizeSdDir(newCacheId)) {
+ errCode = PASS;
+ }
+ }
+ }
+ // Print error based on errCode
+ String errMsg = "";
+ switch (errCode) {
+ case CREATE_FAILED:
+ errMsg = "CREATE_FAILED";
+ break;
+ case COPY_FAILED:
+ errMsg = "COPY_FAILED";
+ destroySdDir(newCacheId);
+ break;
+ case FINALIZE_FAILED:
+ errMsg = "FINALIZE_FAILED";
+ destroySdDir(newCacheId);
+ break;
+ default:
+ errMsg = "PASS";
+ unMountSdDir(newCacheId);
+ break;
+ }
+ Log.i(TAG, "Status: " + errMsg);
+ if (errCode != PASS) {
+ return null;
+ }
+ return newCachePath;
+ }
+
+ private String createSdDir(final Uri packageURI,
+ String containerId, String sdEncKey) {
+ File tmpPackageFile = new File(packageURI.getPath());
+ // Create mount point via MountService
+ IMountService mountService = getMountService();
+ long len = tmpPackageFile.length();
+ int mbLen = (int) (len/(1024*1024));
+ if ((len - (mbLen * 1024 * 1024)) > 0) {
+ mbLen++;
+ }
+ if (localLOGV) Log.i(TAG, "mbLen="+mbLen);
+ String cachePath = null;
+ int ownerUid = Process.myUid();
+ try {
+ cachePath = mountService.createSecureContainer(containerId,
+ mbLen,
+ "vfat", sdEncKey, ownerUid);
+ if (localLOGV) Log.i(TAG, "Trying to create secure container for "
+ + containerId + ", cachePath =" + cachePath);
+ return cachePath;
+ } catch(IllegalStateException e) {
+ Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ return null;
+ }
+ // TODO just fail here and let the user delete later on.
+ try {
+ mountService.destroySecureContainer(containerId);
+ if (localLOGV) Log.i(TAG, "Destroying cache for " + containerId
+ + ", cachePath =" + cachePath);
+ } catch(IllegalStateException e) {
+ Log.e(TAG, "Failed to destroy existing cache: " + e);
+ return null;
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ return null;
+ }
+ try {
+ cachePath = mountService.createSecureContainer(containerId,
+ mbLen,
+ "vfat", sdEncKey, ownerUid);
+ if (localLOGV) Log.i(TAG, "Trying to install again " + containerId
+ + ", cachePath =" + cachePath);
+ return cachePath;
+ } catch(IllegalStateException e) {
+ Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ }
+ return null;
+ }
+
+ private boolean destroySdDir(String containerId) {
+ try {
+ // We need to destroy right away
+ getMountService().destroySecureContainer(containerId);
+ return true;
+ } catch (IllegalStateException e) {
+ Log.i(TAG, "Failed to destroy container : " + containerId);
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ }
+ return false;
+ }
+
+ private boolean finalizeSdDir(String containerId){
+ try {
+ getMountService().finalizeSecureContainer(containerId);
+ return true;
+ } catch (IllegalStateException e) {
+ Log.i(TAG, "Failed to finalize container for pkg : " + containerId);
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ }
+ return false;
+ }
+
+ private boolean unMountSdDir(String containerId) {
+ try {
+ getMountService().unmountSecureContainer(containerId);
+ return true;
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to unmount id: " + containerId + " with exception " + e);
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ }
+ return false;
+ }
+
+ private String mountSdDir(String containerId, String key) {
+ try {
+ return getMountService().mountSecureContainer(containerId, key, Process.myUid());
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to mount id: " +
+ containerId + " with exception " + e);
+ } catch(RemoteException e) {
+ Log.e(TAG, "MounteService not running?");
+ }
+ return null;
+ }
+
+ public static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
+ try {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = inputStream.read(buffer)) >= 0) {
+ out.write(buffer, 0, bytesRead);
+ }
+ return true;
+ } catch (IOException e) {
+ Log.i(TAG, "Exception : " + e + " when copying file");
+ return false;
+ }
+ }
+
+ public static boolean copyToFile(File srcFile, FileOutputStream out) {
+ InputStream inputStream = null;
+ try {
+ inputStream = new FileInputStream(srcFile);
+ return copyToFile(inputStream, out);
+ } catch (IOException e) {
+ return false;
+ } finally {
+ try { if (inputStream != null) inputStream.close(); } catch (IOException e) {}
+ }
+ }
+
+ private boolean copyFile(Uri pPackageURI, FileOutputStream outStream) {
+ if (pPackageURI.getScheme().equals("file")) {
+ final File srcPackageFile = new File(pPackageURI.getPath());
+ // We copy the source package file to a temp file and then rename it to the
+ // destination file in order to eliminate a window where the package directory
+ // scanner notices the new package file but it's not completely copied yet.
+ if (!copyToFile(srcPackageFile, outStream)) {
+ Log.e(TAG, "Couldn't copy file: " + srcPackageFile);
+ return false;
+ }
+ } else if (pPackageURI.getScheme().equals("content")) {
+ ParcelFileDescriptor fd = null;
+ try {
+ fd = getContentResolver().openFileDescriptor(pPackageURI, "r");
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
+ return false;
+ }
+ if (fd == null) {
+ Log.e(TAG, "Couldn't open file descriptor from download service (null).");
+ return false;
+ } else {
+ if (localLOGV) {
+ Log.v(TAG, "Opened file descriptor from download service.");
+ }
+ ParcelFileDescriptor.AutoCloseInputStream
+ dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
+ // We copy the source package file to a temp file and then rename it to the
+ // destination file in order to eliminate a window where the package directory
+ // scanner notices the new package file but it's not completely copied yet.
+ if (!copyToFile(dlStream, outStream)) {
+ Log.e(TAG, "Couldn't copy " + pPackageURI + " to temp file.");
+ return false;
+ }
+ }
+ } else {
+ Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
+ return false;
+ }
+ return true;
+ }
+}