diff options
Diffstat (limited to 'packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java')
-rw-r--r-- | packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java | 305 |
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; + } +} |