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