PackageHelper.java revision 6dceb88f1c7c42c6ab43834af2c993d599895d82
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
17package com.android.internal.content;
18
19import android.os.FileUtils;
20import android.os.IBinder;
21import android.os.RemoteException;
22import android.os.ServiceManager;
23import android.os.storage.IMountService;
24import android.os.storage.StorageResultCode;
25import android.util.Log;
26
27import java.io.File;
28import java.io.FileOutputStream;
29import java.io.IOException;
30import java.io.InputStream;
31import java.util.Collections;
32import java.util.zip.ZipEntry;
33import java.util.zip.ZipFile;
34import java.util.zip.ZipOutputStream;
35
36import 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 */
43public 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() {
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        }
67        return null;
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        IMountService mountService = getMountService();
74
75        if (localLOGV)
76            Log.i(TAG, "Size of container " + sizeMb + " MB");
77
78        try {
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