Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2009 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.internal.content;
     18 
     19 import android.os.FileUtils;
     20 import android.os.IBinder;
     21 import android.os.RemoteException;
     22 import android.os.ServiceManager;
     23 import android.os.storage.IMountService;
     24 import android.os.storage.StorageResultCode;
     25 import android.util.Log;
     26 
     27 import java.io.File;
     28 import java.io.FileOutputStream;
     29 import java.io.IOException;
     30 import java.io.InputStream;
     31 import java.util.Collections;
     32 import java.util.zip.ZipEntry;
     33 import java.util.zip.ZipFile;
     34 import java.util.zip.ZipOutputStream;
     35 
     36 import libcore.io.IoUtils;
     37 
     38 /**
     39  * Constants used internally between the PackageManager
     40  * and media container service transports.
     41  * Some utility methods to invoke MountService api.
     42  */
     43 public class PackageHelper {
     44     public static final int RECOMMEND_INSTALL_INTERNAL = 1;
     45     public static final int RECOMMEND_INSTALL_EXTERNAL = 2;
     46     public static final int RECOMMEND_FAILED_INSUFFICIENT_STORAGE = -1;
     47     public static final int RECOMMEND_FAILED_INVALID_APK = -2;
     48     public static final int RECOMMEND_FAILED_INVALID_LOCATION = -3;
     49     public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
     50     public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
     51     public static final int RECOMMEND_FAILED_INVALID_URI = -6;
     52     public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
     53 
     54     private static final boolean localLOGV = false;
     55     private static final String TAG = "PackageHelper";
     56     // App installation location settings values
     57     public static final int APP_INSTALL_AUTO = 0;
     58     public static final int APP_INSTALL_INTERNAL = 1;
     59     public static final int APP_INSTALL_EXTERNAL = 2;
     60 
     61     public static IMountService getMountService() throws RemoteException {
     62         IBinder service = ServiceManager.getService("mount");
     63         if (service != null) {
     64             return IMountService.Stub.asInterface(service);
     65         } else {
     66             Log.e(TAG, "Can't get mount service");
     67             throw new RemoteException("Could not contact mount service");
     68         }
     69     }
     70 
     71     public static String createSdDir(int sizeMb, String cid, String sdEncKey, int uid,
     72             boolean isExternal) {
     73         // Create mount point via MountService
     74         try {
     75             IMountService mountService = getMountService();
     76 
     77             if (localLOGV)
     78                 Log.i(TAG, "Size of container " + sizeMb + " MB");
     79 
     80             int rc = mountService.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid,
     81                     isExternal);
     82             if (rc != StorageResultCode.OperationSucceeded) {
     83                 Log.e(TAG, "Failed to create secure container " + cid);
     84                 return null;
     85             }
     86             String cachePath = mountService.getSecureContainerPath(cid);
     87             if (localLOGV) Log.i(TAG, "Created secure container " + cid +
     88                     " at " + cachePath);
     89                 return cachePath;
     90         } catch (RemoteException e) {
     91             Log.e(TAG, "MountService running?");
     92         }
     93         return null;
     94     }
     95 
     96    public static String mountSdDir(String cid, String key, int ownerUid) {
     97     try {
     98         int rc = getMountService().mountSecureContainer(cid, key, ownerUid);
     99         if (rc != StorageResultCode.OperationSucceeded) {
    100             Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
    101             return null;
    102         }
    103         return getMountService().getSecureContainerPath(cid);
    104     } catch (RemoteException e) {
    105         Log.e(TAG, "MountService running?");
    106     }
    107     return null;
    108    }
    109 
    110    public static boolean unMountSdDir(String cid) {
    111     try {
    112         int rc = getMountService().unmountSecureContainer(cid, true);
    113         if (rc != StorageResultCode.OperationSucceeded) {
    114             Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
    115             return false;
    116         }
    117         return true;
    118     } catch (RemoteException e) {
    119         Log.e(TAG, "MountService running?");
    120     }
    121         return false;
    122    }
    123 
    124    public static boolean renameSdDir(String oldId, String newId) {
    125        try {
    126            int rc = getMountService().renameSecureContainer(oldId, newId);
    127            if (rc != StorageResultCode.OperationSucceeded) {
    128                Log.e(TAG, "Failed to rename " + oldId + " to " +
    129                        newId + "with rc " + rc);
    130                return false;
    131            }
    132            return true;
    133        } catch (RemoteException e) {
    134            Log.i(TAG, "Failed ot rename  " + oldId + " to " + newId +
    135                    " with exception : " + e);
    136        }
    137        return false;
    138    }
    139 
    140    public static String getSdDir(String cid) {
    141        try {
    142             return getMountService().getSecureContainerPath(cid);
    143         } catch (RemoteException e) {
    144             Log.e(TAG, "Failed to get container path for " + cid +
    145                 " with exception " + e);
    146         }
    147         return null;
    148    }
    149 
    150    public static String getSdFilesystem(String cid) {
    151        try {
    152             return getMountService().getSecureContainerFilesystemPath(cid);
    153         } catch (RemoteException e) {
    154             Log.e(TAG, "Failed to get container path for " + cid +
    155                 " with exception " + e);
    156         }
    157         return null;
    158    }
    159 
    160     public static boolean finalizeSdDir(String cid) {
    161         try {
    162             int rc = getMountService().finalizeSecureContainer(cid);
    163             if (rc != StorageResultCode.OperationSucceeded) {
    164                 Log.i(TAG, "Failed to finalize container " + cid);
    165                 return false;
    166             }
    167             return true;
    168         } catch (RemoteException e) {
    169             Log.e(TAG, "Failed to finalize container " + cid +
    170                     " with exception " + e);
    171         }
    172         return false;
    173     }
    174 
    175     public static boolean destroySdDir(String cid) {
    176         try {
    177             if (localLOGV) Log.i(TAG, "Forcibly destroying container " + cid);
    178             int rc = getMountService().destroySecureContainer(cid, true);
    179             if (rc != StorageResultCode.OperationSucceeded) {
    180                 Log.i(TAG, "Failed to destroy container " + cid);
    181                 return false;
    182             }
    183             return true;
    184         } catch (RemoteException e) {
    185             Log.e(TAG, "Failed to destroy container " + cid +
    186                     " with exception " + e);
    187         }
    188         return false;
    189     }
    190 
    191     public static String[] getSecureContainerList() {
    192         try {
    193             return getMountService().getSecureContainerList();
    194         } catch (RemoteException e) {
    195             Log.e(TAG, "Failed to get secure container list with exception" +
    196                     e);
    197         }
    198         return null;
    199     }
    200 
    201    public static boolean isContainerMounted(String cid) {
    202        try {
    203            return getMountService().isSecureContainerMounted(cid);
    204        } catch (RemoteException e) {
    205            Log.e(TAG, "Failed to find out if container " + cid + " mounted");
    206        }
    207        return false;
    208    }
    209 
    210     public static int extractPublicFiles(String packagePath, File publicZipFile)
    211             throws IOException {
    212         final FileOutputStream fstr;
    213         final ZipOutputStream publicZipOutStream;
    214 
    215         if (publicZipFile == null) {
    216             fstr = null;
    217             publicZipOutStream = null;
    218         } else {
    219             fstr = new FileOutputStream(publicZipFile);
    220             publicZipOutStream = new ZipOutputStream(fstr);
    221         }
    222 
    223         int size = 0;
    224 
    225         try {
    226             final ZipFile privateZip = new ZipFile(packagePath);
    227             try {
    228                 // Copy manifest, resources.arsc and res directory to public zip
    229                 for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) {
    230                     final String zipEntryName = zipEntry.getName();
    231                     if ("AndroidManifest.xml".equals(zipEntryName)
    232                             || "resources.arsc".equals(zipEntryName)
    233                             || zipEntryName.startsWith("res/")) {
    234                         size += zipEntry.getSize();
    235                         if (publicZipFile != null) {
    236                             copyZipEntry(zipEntry, privateZip, publicZipOutStream);
    237                         }
    238                     }
    239                 }
    240             } finally {
    241                 try { privateZip.close(); } catch (IOException e) {}
    242             }
    243 
    244             if (publicZipFile != null) {
    245                 publicZipOutStream.finish();
    246                 publicZipOutStream.flush();
    247                 FileUtils.sync(fstr);
    248                 publicZipOutStream.close();
    249                 FileUtils.setPermissions(publicZipFile.getAbsolutePath(), FileUtils.S_IRUSR
    250                         | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
    251             }
    252         } finally {
    253             IoUtils.closeQuietly(publicZipOutStream);
    254         }
    255 
    256         return size;
    257     }
    258 
    259     private static void copyZipEntry(ZipEntry zipEntry, ZipFile inZipFile,
    260             ZipOutputStream outZipStream) throws IOException {
    261         byte[] buffer = new byte[4096];
    262         int num;
    263 
    264         ZipEntry newEntry;
    265         if (zipEntry.getMethod() == ZipEntry.STORED) {
    266             // Preserve the STORED method of the input entry.
    267             newEntry = new ZipEntry(zipEntry);
    268         } else {
    269             // Create a new entry so that the compressed len is recomputed.
    270             newEntry = new ZipEntry(zipEntry.getName());
    271         }
    272         outZipStream.putNextEntry(newEntry);
    273 
    274         final InputStream data = inZipFile.getInputStream(zipEntry);
    275         try {
    276             while ((num = data.read(buffer)) > 0) {
    277                 outZipStream.write(buffer, 0, num);
    278             }
    279             outZipStream.flush();
    280         } finally {
    281             IoUtils.closeQuietly(data);
    282         }
    283     }
    284 
    285     public static boolean fixSdPermissions(String cid, int gid, String filename) {
    286         try {
    287             int rc = getMountService().fixPermissionsSecureContainer(cid, gid, filename);
    288             if (rc != StorageResultCode.OperationSucceeded) {
    289                 Log.i(TAG, "Failed to fixperms container " + cid);
    290                 return false;
    291             }
    292             return true;
    293         } catch (RemoteException e) {
    294             Log.e(TAG, "Failed to fixperms container " + cid + " with exception " + e);
    295         }
    296         return false;
    297     }
    298 }
    299