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