From 85387d7ba36e56b291cbde87acb5a5b2200fe01c Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 26 Aug 2010 10:13:11 -0700 Subject: Allow native shared libraries in ASEC containers This change moves the native library handling earlier in the package installation process so that it may be inserted into ASEC containers before they are finalized in the DefaultContainerService. Note that native libraries on SD card requires that vold mount ASEC containers without the "noexec" flag on the mount point. Change-Id: Ib34b1886bf6f94b99bb7b3781db6e9b5a58807ba --- core/java/android/app/ActivityThread.java | 1 + core/java/android/app/ApplicationLoaders.java | 10 +- core/java/android/app/LoadedApk.java | 8 +- core/java/android/content/pm/ApplicationInfo.java | 20 +- .../android/content/pm/InstrumentationInfo.java | 12 +- .../internal/content/NativeLibraryHelper.java | 296 +++++++++++ .../android/internal/content/PackageHelper.java | 16 +- .../android/content/pm/PackageManagerTests.java | 3 + .../defcontainer/DefaultContainerService.java | 81 ++- .../com/android/server/PackageManagerService.java | 564 +++++++-------------- 10 files changed, 613 insertions(+), 398 deletions(-) create mode 100644 core/java/com/android/internal/content/NativeLibraryHelper.java diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 084f637..ca6fc8a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3181,6 +3181,7 @@ public final class ActivityThread { instrApp.sourceDir = ii.sourceDir; instrApp.publicSourceDir = ii.publicSourceDir; instrApp.dataDir = ii.dataDir; + instrApp.nativeLibraryDir = ii.nativeLibraryDir; LoadedApk pi = getPackageInfo(instrApp, appContext.getClassLoader(), false, true); ContextImpl instrContext = new ContextImpl(); diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 2e301c9..9e3cd7e 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -19,6 +19,7 @@ package android.app; import dalvik.system.PathClassLoader; import java.util.HashMap; +import java.util.Map; class ApplicationLoaders { @@ -27,8 +28,7 @@ class ApplicationLoaders return gApplicationLoaders; } - public ClassLoader getClassLoader(String zip, String appDataDir, - ClassLoader parent) + public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent) { /* * This is the parent we use if they pass "null" in. In theory @@ -49,13 +49,13 @@ class ApplicationLoaders * new ClassLoader for the zip archive. */ if (parent == baseParent) { - ClassLoader loader = (ClassLoader)mLoaders.get(zip); + ClassLoader loader = mLoaders.get(zip); if (loader != null) { return loader; } PathClassLoader pathClassloader = - new PathClassLoader(zip, appDataDir + "/lib", parent); + new PathClassLoader(zip, libPath, parent); mLoaders.put(zip, pathClassloader); return pathClassloader; @@ -65,7 +65,7 @@ class ApplicationLoaders } } - private final HashMap mLoaders = new HashMap(); + private final Map mLoaders = new HashMap(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 0f98152..0644f96 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -72,6 +72,7 @@ final class LoadedApk { private final String mResDir; private final String[] mSharedLibraries; private final String mDataDir; + private final String mLibDir; private final File mDataDirFile; private final ClassLoader mBaseClassLoader; private final boolean mSecurityViolation; @@ -108,6 +109,7 @@ final class LoadedApk { mSharedLibraries = aInfo.sharedLibraryFiles; mDataDir = aInfo.dataDir; mDataDirFile = mDataDir != null ? new File(mDataDir) : null; + mLibDir = aInfo.nativeLibraryDir; mBaseClassLoader = baseLoader; mSecurityViolation = securityViolation; mIncludeCode = includeCode; @@ -140,6 +142,7 @@ final class LoadedApk { mSharedLibraries = null; mDataDir = null; mDataDirFile = null; + mLibDir = null; mBaseClassLoader = null; mSecurityViolation = false; mIncludeCode = true; @@ -279,11 +282,12 @@ final class LoadedApk { * create the class loader. */ - if (ActivityThread.localLOGV) Slog.v(ActivityThread.TAG, "Class path: " + zip); + if (ActivityThread.localLOGV) + Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir); mClassLoader = ApplicationLoaders.getDefault().getClassLoader( - zip, mDataDir, mBaseClassLoader); + zip, mLibDir, mBaseClassLoader); initializeJavaContextClassLoader(); } else { if (mBaseClassLoader == null) { diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index c812f36..ae6a311 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -291,14 +291,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_FORWARD_LOCK = 1<<29; /** - * Value for {@link #flags}: Set to true if the application is - * native-debuggable, i.e. embeds a gdbserver binary in its .apk - * - * {@hide} - */ - public static final int FLAG_NATIVE_DEBUGGABLE = 1<<28; - - /** * Value for {@link #flags}: set to true if the application * has reported that it is heavy-weight, and thus can not participate in * the normal application lifecycle. @@ -359,7 +351,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * data. */ public String dataDir; - + + /** + * Full path to the directory where native JNI libraries are stored. + * + * {@hide} + */ + public String nativeLibraryDir; + /** * The kernel user-ID that has been assigned to this application; * currently this is not a unique ID (multiple applications can have @@ -452,6 +451,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { flags = orig.flags; sourceDir = orig.sourceDir; publicSourceDir = orig.publicSourceDir; + nativeLibraryDir = orig.nativeLibraryDir; resourceDirs = orig.resourceDirs; sharedLibraryFiles = orig.sharedLibraryFiles; dataDir = orig.dataDir; @@ -483,6 +483,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(flags); dest.writeString(sourceDir); dest.writeString(publicSourceDir); + dest.writeString(nativeLibraryDir); dest.writeStringArray(resourceDirs); dest.writeStringArray(sharedLibraryFiles); dest.writeString(dataDir); @@ -514,6 +515,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { flags = source.readInt(); sourceDir = source.readString(); publicSourceDir = source.readString(); + nativeLibraryDir = source.readString(); resourceDirs = source.readStringArray(); sharedLibraryFiles = source.readStringArray(); dataDir = source.readString(); diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java index 3e868a7..ea47e8e 100644 --- a/core/java/android/content/pm/InstrumentationInfo.java +++ b/core/java/android/content/pm/InstrumentationInfo.java @@ -50,7 +50,14 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { * data. */ public String dataDir; - + + /** + * Full path to the directory where the native JNI libraries are stored. + * + * {@hide} + */ + public String nativeLibraryDir; + /** * Specifies whether or not this instrumentation will handle profiling. */ @@ -68,6 +75,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { sourceDir = orig.sourceDir; publicSourceDir = orig.publicSourceDir; dataDir = orig.dataDir; + nativeLibraryDir = orig.nativeLibraryDir; handleProfiling = orig.handleProfiling; functionalTest = orig.functionalTest; } @@ -88,6 +96,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { dest.writeString(sourceDir); dest.writeString(publicSourceDir); dest.writeString(dataDir); + dest.writeString(nativeLibraryDir); dest.writeInt((handleProfiling == false) ? 0 : 1); dest.writeInt((functionalTest == false) ? 0 : 1); } @@ -108,6 +117,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { sourceDir = source.readString(); publicSourceDir = source.readString(); dataDir = source.readString(); + nativeLibraryDir = source.readString(); handleProfiling = source.readInt() != 0; functionalTest = source.readInt() != 0; } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java new file mode 100644 index 0000000..8b618c7 --- /dev/null +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -0,0 +1,296 @@ +package com.android.internal.content; + +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.FileUtils; +import android.os.SystemProperties; +import android.util.Config; +import android.util.Log; +import android.util.Pair; +import android.util.Slog; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * Native libraries helper. + * + * @hide + */ +public class NativeLibraryHelper { + private static final String TAG = "NativeHelper"; + + private static final boolean DEBUG_NATIVE = false; + + /* + * The following constants are returned by listPackageSharedLibsForAbiLI + * to indicate if native shared libraries were found in the package. + * Values are: + * PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed + * PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package + * PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found + * in package (and not installed) + * + */ + private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0; + private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1; + private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2; + + // Directory in the APK that holds all the native shared libraries. + private static final String APK_LIB = "lib/"; + private static final int APK_LIB_LENGTH = APK_LIB.length(); + + // Prefix that native shared libraries must have. + private static final String LIB_PREFIX = "lib"; + private static final int LIB_PREFIX_LENGTH = LIB_PREFIX.length(); + + // Suffix that the native shared libraries must have. + private static final String LIB_SUFFIX = ".so"; + private static final int LIB_SUFFIX_LENGTH = LIB_SUFFIX.length(); + + // Name of the GDB binary. + private static final String GDBSERVER = "gdbserver"; + + // the minimum length of a valid native shared library of the form + // lib//lib.so. + private static final int MIN_ENTRY_LENGTH = APK_LIB_LENGTH + 2 + LIB_PREFIX_LENGTH + 1 + + LIB_SUFFIX_LENGTH; + + /* + * Find all files of the form lib//lib.so in the .apk + * and add them to a list to be installed later. + * + * NOTE: this method may throw an IOException if the library cannot + * be copied to its final destination, e.g. if there isn't enough + * room left on the data partition, or a ZipException if the package + * file is malformed. + */ + private static int listPackageSharedLibsForAbiLI(ZipFile zipFile, + String cpuAbi, List> libEntries) throws IOException, + ZipException { + final int cpuAbiLen = cpuAbi.length(); + boolean hasNativeLibraries = false; + boolean installedNativeLibraries = false; + + if (DEBUG_NATIVE) { + Slog.d(TAG, "Checking " + zipFile.getName() + " for shared libraries of CPU ABI type " + + cpuAbi); + } + + Enumeration entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + + // skip directories + if (entry.isDirectory()) { + continue; + } + String entryName = entry.getName(); + + /* + * Check that the entry looks like lib//lib.so + * here, but don't check the ABI just yet. + * + * - must be sufficiently long + * - must end with LIB_SUFFIX, i.e. ".so" + * - must start with APK_LIB, i.e. "lib/" + */ + if (entryName.length() < MIN_ENTRY_LENGTH || !entryName.endsWith(LIB_SUFFIX) + || !entryName.startsWith(APK_LIB)) { + continue; + } + + // file name must start with LIB_PREFIX, i.e. "lib" + int lastSlash = entryName.lastIndexOf('/'); + + if (lastSlash < 0 + || !entryName.regionMatches(lastSlash + 1, LIB_PREFIX, 0, LIB_PREFIX_LENGTH)) { + continue; + } + + hasNativeLibraries = true; + + // check the cpuAbi now, between lib/ and /lib.so + if (lastSlash != APK_LIB_LENGTH + cpuAbiLen + || !entryName.regionMatches(APK_LIB_LENGTH, cpuAbi, 0, cpuAbiLen)) + continue; + + /* + * Extract the library file name, ensure it doesn't contain + * weird characters. we're guaranteed here that it doesn't contain + * a directory separator though. + */ + String libFileName = entryName.substring(lastSlash+1); + if (!FileUtils.isFilenameSafe(new File(libFileName))) { + continue; + } + + installedNativeLibraries = true; + + if (DEBUG_NATIVE) { + Log.d(TAG, "Caching shared lib " + entry.getName()); + } + + libEntries.add(Pair.create(entry, libFileName)); + } + if (!hasNativeLibraries) + return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; + + if (!installedNativeLibraries) + return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH; + + return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; + } + + /* + * Find the gdbserver executable program in a package at + * lib//gdbserver and add it to the list of binaries + * to be copied out later. + * + * Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success, + * or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise. + */ + private static int listPackageGdbServerLI(ZipFile zipFile, String cpuAbi, + List> nativeFiles) throws IOException, ZipException { + final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER; + + Enumeration entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + // skip directories + if (entry.isDirectory()) { + continue; + } + String entryName = entry.getName(); + + if (!entryName.equals(apkGdbServerPath)) { + continue; + } + + if (Config.LOGD) { + Log.d(TAG, "Found gdbserver: " + entry.getName()); + } + + final String installGdbServerPath = APK_LIB + GDBSERVER; + nativeFiles.add(Pair.create(entry, installGdbServerPath)); + + return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; + } + return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; + } + + /* + * Examine shared libraries stored in the APK as + * lib//lib.so and add them to a list to be copied + * later. + * + * This function will first try the main CPU ABI defined by Build.CPU_ABI + * (which corresponds to ro.product.cpu.abi), and also try an alternate + * one if ro.product.cpu.abi2 is defined. + */ + public static int listPackageNativeBinariesLI(ZipFile zipFile, + List> nativeFiles) throws ZipException, IOException { + String cpuAbi = Build.CPU_ABI; + + int result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi, nativeFiles); + + /* + * Some architectures are capable of supporting several CPU ABIs + * for example, 'armeabi-v7a' also supports 'armeabi' native code + * this is indicated by the definition of the ro.product.cpu.abi2 + * system property. + * + * only scan the package twice in case of ABI mismatch + */ + if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { + final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2", null); + if (cpuAbi2 != null) { + result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi2, nativeFiles); + } + + if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { + Slog.w(TAG, "Native ABI mismatch from package file"); + return PackageManager.INSTALL_FAILED_INVALID_APK; + } + + if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { + cpuAbi = cpuAbi2; + } + } + + /* + * Debuggable packages may have gdbserver embedded, so add it to + * the list to the list of items to be extracted (as lib/gdbserver) + * into the application's native library directory later. + */ + if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { + listPackageGdbServerLI(zipFile, cpuAbi, nativeFiles); + } + return PackageManager.INSTALL_SUCCEEDED; + } + + public static int copyNativeBinariesLI(File scanFile, File sharedLibraryDir) { + /* + * Check all the native files that need to be copied and add + * that to the container size. + */ + ZipFile zipFile; + try { + zipFile = new ZipFile(scanFile); + + List> nativeFiles = new LinkedList>(); + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + + for (int i = 0; i < N; i++) { + final Pair entry = nativeFiles.get(i); + + File destFile = new File(sharedLibraryDir, entry.second); + copyNativeBinaryLI(zipFile, entry.first, sharedLibraryDir, destFile); + } + } catch (ZipException e) { + Slog.w(TAG, "Failed to extract data from package file", e); + return PackageManager.INSTALL_FAILED_INVALID_APK; + } catch (IOException e) { + Slog.w(TAG, "Failed to cache package shared libs", e); + return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } + + return PackageManager.INSTALL_SUCCEEDED; + } + + private static void copyNativeBinaryLI(ZipFile zipFile, ZipEntry entry, + File binaryDir, File binaryFile) throws IOException { + InputStream inputStream = zipFile.getInputStream(entry); + try { + File tempFile = File.createTempFile("tmp", "tmp", binaryDir); + String tempFilePath = tempFile.getPath(); + // XXX package manager can't change owner, so the executable files for + // now need to be left as world readable and owned by the system. + if (!FileUtils.copyToFile(inputStream, tempFile) + || !tempFile.setLastModified(entry.getTime()) + || FileUtils.setPermissions(tempFilePath, FileUtils.S_IRUSR | FileUtils.S_IWUSR + | FileUtils.S_IRGRP | FileUtils.S_IXUSR | FileUtils.S_IXGRP + | FileUtils.S_IXOTH | FileUtils.S_IROTH, -1, -1) != 0 + || !tempFile.renameTo(binaryFile)) { + // Failed to properly write file. + tempFile.delete(); + throw new IOException("Couldn't create cached binary " + binaryFile + " in " + + binaryDir); + } + } finally { + inputStream.close(); + } + } +} diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 4d0a9e0..d6c43f9 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -56,22 +56,22 @@ public class PackageHelper { return null; } - public static String createSdDir(File tmpPackageFile, String cid, + public static String createSdDir(long sizeBytes, String cid, String sdEncKey, int uid) { // Create mount point via MountService IMountService mountService = getMountService(); - long len = tmpPackageFile.length(); - int mbLen = (int) (len >> 20); - if ((len - (mbLen * 1024 * 1024)) > 0) { - mbLen++; + int sizeMb = (int) (sizeBytes >> 20); + if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) { + sizeMb++; } // Add buffer size - mbLen++; - if (localLOGV) Log.i(TAG, "Size of container " + mbLen + " MB " + len + " bytes"); + sizeMb++; + if (localLOGV) + Log.i(TAG, "Size of container " + sizeMb + " MB " + sizeBytes + " bytes"); try { int rc = mountService.createSecureContainer( - cid, mbLen, "fat", sdEncKey, uid); + cid, sizeMb, "fat", sdEncKey, uid); if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to create secure container " + cid); return null; diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index cbf8c87..de3d153 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -358,6 +358,7 @@ public class PackageManagerTests extends AndroidTestCase { assertTrue((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); assertEquals(srcPath, drmInstallPath); assertEquals(publicSrcPath, appInstallPath); + assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath())); } else { assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); int rLoc = getInstallLoc(flags, expInstallLocation, pkgLen); @@ -365,10 +366,12 @@ public class PackageManagerTests extends AndroidTestCase { assertEquals(srcPath, appInstallPath); assertEquals(publicSrcPath, appInstallPath); assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath())); } else if (rLoc == INSTALL_LOC_SD){ assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX)); assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX)); } else { // TODO handle error. Install should have failed. } diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index c6e0a24..f08bd3c 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -17,7 +17,9 @@ package com.android.defcontainer; import com.android.internal.app.IMediaContainerService; +import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; + import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; @@ -37,6 +39,7 @@ import android.os.StatFs; import android.app.IntentService; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Pair; import java.io.File; import java.io.FileInputStream; @@ -44,6 +47,11 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; import android.os.FileUtils; import android.provider.Settings; @@ -59,6 +67,8 @@ public class DefaultContainerService extends IntentService { private static final String TAG = "DefContainer"; private static final boolean localLOGV = true; + private static final String LIB_DIR_NAME = "lib"; + private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() { /* * Creates a new container and copies resource there. @@ -194,18 +204,51 @@ public class DefaultContainerService extends IntentService { Log.w(TAG, "Make sure sdcard is mounted."); return null; } - // Create new container at newCachePath + + // The .apk file String codePath = packageURI.getPath(); File codeFile = new File(codePath); - String newCachePath = null; + + // Calculate size of container needed to hold base APK. + long sizeBytes = codeFile.length(); + + // Check all the native files that need to be copied and add that to the container size. + ZipFile zipFile; + List> nativeFiles; + try { + zipFile = new ZipFile(codeFile); + + nativeFiles = new LinkedList>(); + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + for (int i = 0; i < N; i++) { + final Pair entry = nativeFiles.get(i); + + /* + * Note that PackageHelper.createSdDir adds a 1MB padding on + * our claimed size, so we don't have to worry about block + * alignment here. + */ + sizeBytes += entry.first.getSize(); + } + } catch (ZipException e) { + Log.w(TAG, "Failed to extract data from package file", e); + return null; + } catch (IOException e) { + Log.w(TAG, "Failed to cache package shared libs", e); + return null; + } + // Create new container - if ((newCachePath = PackageHelper.createSdDir(codeFile, - newCid, key, Process.myUid())) == null) { + String newCachePath = null; + if ((newCachePath = PackageHelper.createSdDir(sizeBytes, newCid, key, Process.myUid())) == null) { Log.e(TAG, "Failed to create container " + newCid); return null; } - if (localLOGV) Log.i(TAG, "Created container for " + newCid - + " at path : " + newCachePath); + if (localLOGV) + Log.i(TAG, "Created container for " + newCid + " at path : " + newCachePath); File resFile = new File(newCachePath, resFileName); if (!FileUtils.copyFile(new File(codePath), resFile)) { Log.e(TAG, "Failed to copy " + codePath + " to " + resFile); @@ -213,6 +256,32 @@ public class DefaultContainerService extends IntentService { PackageHelper.destroySdDir(newCid); return null; } + + try { + File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); + sharedLibraryDir.mkdir(); + + final int N = nativeFiles.size(); + for (int i = 0; i < N; i++) { + final Pair entry = nativeFiles.get(i); + + InputStream is = zipFile.getInputStream(entry.first); + try { + File destFile = new File(sharedLibraryDir, entry.second); + if (!FileUtils.copyToFile(is, destFile)) { + throw new IOException("Couldn't copy native binary " + + entry.first.getName() + " to " + entry.second); + } + } finally { + is.close(); + } + } + } catch (IOException e) { + Log.e(TAG, "Couldn't copy native file to container", e); + PackageHelper.destroySdDir(newCid); + return null; + } + if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); if (!PackageHelper.finalizeSdDir(newCid)) { Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 0ff33d1..a2d3298 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -18,6 +18,7 @@ package com.android.server; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; +import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; @@ -112,6 +113,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -188,6 +190,8 @@ class PackageManagerService extends IPackageManager.Stub { "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); + private static final String LIB_DIR_NAME = "lib"; + static final String mTempContainerPrefix = "smdl2tmp"; final HandlerThread mHandlerThread = new HandlerThread("PackageManager", @@ -678,13 +682,6 @@ class PackageManagerService extends IPackageManager.Stub { return false; } - static boolean isFwdLocked(int flags) { - if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { - return true; - } - return false; - } - public static final IPackageManager main(Context context, boolean factoryTest) { PackageManagerService m = new PackageManagerService(context, factoryTest); ServiceManager.addService("package", m); @@ -1497,6 +1494,7 @@ class PackageManagerService extends IPackageManager.Stub { ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString; ps.pkg.applicationInfo.sourceDir = ps.codePathString; ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath(); + ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; ps.pkg.mSetEnabled = ps.enabled; } return generatePackageInfo(ps.pkg, flags); @@ -2376,8 +2374,7 @@ class PackageManagerService extends IPackageManager.Stub { PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 - && (!mSafeMode || (p.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { + && (!mSafeMode || isSystemApp(p))) { finalList.add(PackageParser.generateApplicationInfo(p, flags)); } } @@ -2621,9 +2618,9 @@ class PackageManagerService extends IPackageManager.Stub { + "reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); - InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString); + InstallArgs args = new FileInstallArgs(ps.codePathString, + ps.resourcePathString, ps.nativeLibraryPathString); args.cleanUpResourcesLI(); - removeNativeBinariesLI(pkg); mSettings.enableSystemPackageLP(ps.name); } } @@ -2663,8 +2660,8 @@ class PackageManagerService extends IPackageManager.Stub { return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE); } - private static void setApplicationInfoPaths(PackageParser.Package pkg, - String destCodePath, String destResPath) { + private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath, + String destResPath) { pkg.mPath = pkg.mScanPath = destCodePath; pkg.applicationInfo.sourceDir = destCodePath; pkg.applicationInfo.publicSourceDir = destResPath; @@ -3146,10 +3143,10 @@ class PackageManagerService extends IPackageManager.Stub { if (dataPath.exists()) { mOutPermissions[1] = 0; FileUtils.getPermissions(dataPath.getPath(), mOutPermissions); - if (mOutPermissions[1] == pkg.applicationInfo.uid - || !Process.supportsProcesses()) { - pkg.applicationInfo.dataDir = dataPath.getPath(); - } else { + + // If we have mismatched owners for the data path, we have a + // problem (unless we're running in the simulator.) + if (mOutPermissions[1] != pkg.applicationInfo.uid && Process.supportsProcesses()) { boolean recovered = false; if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { // If this is a system app, we can at least delete its @@ -3186,6 +3183,7 @@ class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.dataDir = "/mismatched_uid/settings_" + pkg.applicationInfo.uid + "/fs_" + mOutPermissions[1]; + pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir; String msg = "Package " + pkg.packageName + " has mismatched uid: " + mOutPermissions[1] + " on disk, " @@ -3229,32 +3227,38 @@ class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.dataDir = null; } } - + + /* + * Set the data dir to the default "/data/data//lib" + * if we got here without anyone telling us different (e.g., apps + * stored on SD card have their native libraries stored in the ASEC + * container with the APK). + */ + if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) { + pkg.applicationInfo.nativeLibraryDir = new File(dataPath, LIB_DIR_NAME).getPath(); + } + pkgSetting.uidError = uidError; } - // Perform shared library installation and dex validation and - // optimization, if this is not a system app. + // If we're running in the simulator, we don't need to unpack anything. if (mInstaller != null) { String path = scanFile.getPath(); - if (scanFileNewer) { - // Note: We don't want to unpack the native binaries for - // system applications, unless they have been updated - // (the binaries are already under /system/lib). - // - // In other words, we're going to unpack the binaries - // only for non-system apps and system app upgrades. - // - int flags = pkg.applicationInfo.flags; - if ((flags & ApplicationInfo.FLAG_SYSTEM) == 0 || - (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { - Log.i(TAG, path + " changed; unpacking"); - int err = cachePackageSharedLibsLI(pkg, scanFile); - if (err != PackageManager.INSTALL_SUCCEEDED) { - mLastScanError = err; - return null; - } - } + /* Note: We don't want to unpack the native binaries for + * system applications, unless they have been updated + * (the binaries are already under /system/lib). + * Also, don't unpack libs for apps on the external card + * since they should have their libraries in the ASEC + * container already. + * + * In other words, we're going to unpack the binaries + * only for non-system apps and system app upgrades. + */ + if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) { + Log.i(TAG, path + " changed; unpacking"); + File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); + sharedLibraryDir.mkdir(); + NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir); } pkg.mScanPath = path; @@ -3517,6 +3521,7 @@ class PackageManagerService extends IPackageManager.Stub { a.info.sourceDir = pkg.applicationInfo.sourceDir; a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; a.info.dataDir = pkg.applicationInfo.dataDir; + a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; mInstrumentation.put(a.getComponentName(), a); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { @@ -3557,266 +3562,30 @@ class PackageManagerService extends IPackageManager.Stub { } } - // The following constants are returned by cachePackageSharedLibsForAbiLI - // to indicate if native shared libraries were found in the package. - // Values are: - // PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed - // PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package - // PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found - // in package (and not installed) - // - private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0; - private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1; - private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2; - // Return the path of the directory that will contain the native binaries // of a given installed package. This is relative to the data path. // - private static File getNativeBinaryDirForPackage(PackageParser.Package pkg) { - return new File(pkg.applicationInfo.dataDir + "/lib"); - } - - // Find all files of the form lib//lib.so in the .apk - // and automatically copy them to /data/data//lib if present. - // - // NOTE: this method may throw an IOException if the library cannot - // be copied to its final destination, e.g. if there isn't enough - // room left on the data partition, or a ZipException if the package - // file is malformed. - // - private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg, - File scanFile, String cpuAbi) throws IOException, ZipException { - File sharedLibraryDir = getNativeBinaryDirForPackage(pkg); - final String apkLib = "lib/"; - final int apkLibLen = apkLib.length(); - final int cpuAbiLen = cpuAbi.length(); - final String libPrefix = "lib"; - final int libPrefixLen = libPrefix.length(); - final String libSuffix = ".so"; - final int libSuffixLen = libSuffix.length(); - boolean hasNativeLibraries = false; - boolean installedNativeLibraries = false; - - // the minimum length of a valid native shared library of the form - // lib//lib.so. - final int minEntryLen = apkLibLen + 2 + libPrefixLen + 1 + libSuffixLen; - - ZipFile zipFile = new ZipFile(scanFile); - Enumeration entries = - (Enumeration) zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - // skip directories - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - - // check that the entry looks like lib//lib.so - // here, but don't check the ABI just yet. - // - // - must be sufficiently long - // - must end with libSuffix, i.e. ".so" - // - must start with apkLib, i.e. "lib/" - if (entryName.length() < minEntryLen || - !entryName.endsWith(libSuffix) || - !entryName.startsWith(apkLib) ) { - continue; - } - - // file name must start with libPrefix, i.e. "lib" - int lastSlash = entryName.lastIndexOf('/'); - - if (lastSlash < 0 || - !entryName.regionMatches(lastSlash+1, libPrefix, 0, libPrefixLen) ) { - continue; - } - - hasNativeLibraries = true; - - // check the cpuAbi now, between lib/ and /lib.so - // - if (lastSlash != apkLibLen + cpuAbiLen || - !entryName.regionMatches(apkLibLen, cpuAbi, 0, cpuAbiLen) ) - continue; - - // extract the library file name, ensure it doesn't contain - // weird characters. we're guaranteed here that it doesn't contain - // a directory separator though. - String libFileName = entryName.substring(lastSlash+1); - if (!FileUtils.isFilenameSafe(new File(libFileName))) { - continue; - } - - installedNativeLibraries = true; - - // Always extract the shared library - String sharedLibraryFilePath = sharedLibraryDir.getPath() + - File.separator + libFileName; - File sharedLibraryFile = new File(sharedLibraryFilePath); - - if (Config.LOGD) { - Log.d(TAG, "Caching shared lib " + entry.getName()); - } - if (mInstaller == null) { - sharedLibraryDir.mkdir(); - } - cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir, - sharedLibraryFile); - } - if (!hasNativeLibraries) - return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; - - if (!installedNativeLibraries) - return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH; - - return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; - } - - // Find the gdbserver executable program in a package at - // lib//gdbserver and copy it to /data/data//lib/gdbserver - // - // Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success, - // or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise. - // - private int cachePackageGdbServerLI(PackageParser.Package pkg, - File scanFile, String cpuAbi) throws IOException, ZipException { - File installGdbServerDir = getNativeBinaryDirForPackage(pkg); - final String GDBSERVER = "gdbserver"; - final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER; - - ZipFile zipFile = new ZipFile(scanFile); - Enumeration entries = - (Enumeration) zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - // skip directories - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - - if (!entryName.equals(apkGdbServerPath)) { - continue; - } - - String installGdbServerPath = installGdbServerDir.getPath() + - "/" + GDBSERVER; - File installGdbServerFile = new File(installGdbServerPath); - - if (Config.LOGD) { - Log.d(TAG, "Caching gdbserver " + entry.getName()); - } - if (mInstaller == null) { - installGdbServerDir.mkdir(); - } - cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir, - installGdbServerFile); - - return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; - } - return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; - } - - // extract shared libraries stored in the APK as lib//lib.so - // and copy them to /data/data//lib. - // - // This function will first try the main CPU ABI defined by Build.CPU_ABI - // (which corresponds to ro.product.cpu.abi), and also try an alternate - // one if ro.product.cpu.abi2 is defined. - // - private int cachePackageSharedLibsLI(PackageParser.Package pkg, File scanFile) { - // Remove all native binaries from a directory. This is used when upgrading - // a package: in case the new .apk doesn't contain a native binary that was - // in the old one (and thus installed), we need to remove it from - // /data/data//lib - // - // The simplest way to do that is to remove all files in this directory, - // since it is owned by "system", applications are not supposed to write - // anything there. - removeNativeBinariesLI(pkg); - - String cpuAbi = Build.CPU_ABI; - try { - int result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi); - - // some architectures are capable of supporting several CPU ABIs - // for example, 'armeabi-v7a' also supports 'armeabi' native code - // this is indicated by the definition of the ro.product.cpu.abi2 - // system property. - // - // only scan the package twice in case of ABI mismatch - if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { - final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null); - if (cpuAbi2 != null) { - result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi2); - } - - if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { - Slog.w(TAG,"Native ABI mismatch from package file"); - return PackageManager.INSTALL_FAILED_INVALID_APK; - } - - if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { - cpuAbi = cpuAbi2; - } - } - - // for debuggable packages, also extract gdbserver from lib/ - // into /data/data//lib too. - if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES && - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { - int result2 = cachePackageGdbServerLI(pkg, scanFile, cpuAbi); - if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE; - } - } - } catch (ZipException e) { - Slog.w(TAG, "Failed to extract data from package file", e); - return PackageManager.INSTALL_FAILED_INVALID_APK; - } catch (IOException e) { - Slog.w(TAG, "Failed to cache package shared libs", e); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + private File getNativeBinaryDirForPackage(PackageParser.Package pkg) { + final String nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; + if (nativeLibraryDir != null) { + return new File(nativeLibraryDir); + } else { + // Fall back for old packages + return new File(pkg.applicationInfo.dataDir, LIB_DIR_NAME); } - return PackageManager.INSTALL_SUCCEEDED; } - private void cacheNativeBinaryLI(PackageParser.Package pkg, - ZipFile zipFile, ZipEntry entry, - File binaryDir, - File binaryFile) throws IOException { - InputStream inputStream = zipFile.getInputStream(entry); - try { - File tempFile = File.createTempFile("tmp", "tmp", binaryDir); - String tempFilePath = tempFile.getPath(); - // XXX package manager can't change owner, so the executable files for - // now need to be left as world readable and owned by the system. - if (! FileUtils.copyToFile(inputStream, tempFile) || - ! tempFile.setLastModified(entry.getTime()) || - FileUtils.setPermissions(tempFilePath, - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP - |FileUtils.S_IXUSR|FileUtils.S_IXGRP|FileUtils.S_IXOTH - |FileUtils.S_IROTH, -1, -1) != 0 || - ! tempFile.renameTo(binaryFile)) { - // Failed to properly write file. - tempFile.delete(); - throw new IOException("Couldn't create cached binary " - + binaryFile + " in " + binaryDir); - } - } finally { - inputStream.close(); - } + // Convenience call for removeNativeBinariesLI(File) + private void removeNativeBinariesLI(PackageParser.Package pkg) { + File nativeLibraryDir = getNativeBinaryDirForPackage(pkg); + removeNativeBinariesLI(nativeLibraryDir); } // Remove the native binaries of a given package. This simply // gets rid of the files in the 'lib' sub-directory. - private void removeNativeBinariesLI(PackageParser.Package pkg) { - File binaryDir = getNativeBinaryDirForPackage(pkg); - + public void removeNativeBinariesLI(File binaryDir) { if (DEBUG_NATIVE) { - Slog.w(TAG,"Deleting native binaries from: " + binaryDir.getPath()); + Slog.w(TAG, "Deleting native binaries from: " + binaryDir.getPath()); } // Just remove any file in the directory. Since the directory @@ -3824,15 +3593,14 @@ class PackageManagerService extends IPackageManager.Stub { // to have written anything there. // if (binaryDir.exists()) { - File[] binaries = binaryDir.listFiles(); + File[] binaries = binaryDir.listFiles(); if (binaries != null) { - for (int nn=0; nn < binaries.length; nn++) { + for (int nn = 0; nn < binaries.length; nn++) { if (DEBUG_NATIVE) { - Slog.d(TAG," Deleting " + binaries[nn].getName()); + Slog.d(TAG, " Deleting " + binaries[nn].getName()); } if (!binaries[nn].delete()) { - Slog.w(TAG,"Could not delete native binary: " + - binaries[nn].getPath()); + Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); } } } @@ -4144,11 +3912,10 @@ class PackageManagerService extends IPackageManager.Stub { || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH); if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + if (isSystemApp(pkg)) { // For updated system applications, the signatureOrSystem permission // is granted only if it had been defined by the original application. - if ((pkg.applicationInfo.flags - & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + if (isUpdatedSystemApp(pkg)) { PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName); if(sysPs.grantedPermissions.contains(perm)) { allowed = true; @@ -4936,7 +4703,7 @@ class PackageManagerService extends IPackageManager.Stub { // App explictly prefers external. Let policy decide } else { // Prefer previous location - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { + if (isExternal(pkg)) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } return PackageHelper.RECOMMEND_INSTALL_INTERNAL; @@ -5048,16 +4815,16 @@ class PackageManagerService extends IPackageManager.Stub { final InstallArgs srcArgs; final InstallArgs targetArgs; int mRet; - MoveParams(InstallArgs srcArgs, - IPackageMoveObserver observer, - int flags, String packageName) { + + MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags, + String packageName, String dataDir) { this.srcArgs = srcArgs; this.observer = observer; this.flags = flags; this.packageName = packageName; if (srcArgs != null) { Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath())); - targetArgs = createInstallArgs(packageUri, flags, packageName); + targetArgs = createInstallArgs(packageUri, flags, packageName, dataDir); } else { targetArgs = null; } @@ -5113,21 +4880,22 @@ class PackageManagerService extends IPackageManager.Stub { } } - private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) { + private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath, + String nativeLibraryPath) { if (installOnSd(flags)) { - return new SdInstallArgs(fullCodePath, fullResourcePath); + return new SdInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath); } else { - return new FileInstallArgs(fullCodePath, fullResourcePath); + return new FileInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath); } } - private InstallArgs createInstallArgs(Uri packageURI, int flags, - String pkgName) { + // Used by package mover + private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName, String dataDir) { if (installOnSd(flags)) { String cid = getNextCodePath(null, pkgName, "/" + SdInstallArgs.RES_FILE_NAME); return new SdInstallArgs(packageURI, cid); } else { - return new FileInstallArgs(packageURI, pkgName); + return new FileInstallArgs(packageURI, pkgName, dataDir); } } @@ -5154,6 +4922,7 @@ class PackageManagerService extends IPackageManager.Stub { abstract int doPostInstall(int status); abstract String getCodePath(); abstract String getResourcePath(); + abstract String getNativeLibraryPath(); // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); abstract boolean doPostDeleteLI(boolean delete); @@ -5164,6 +4933,7 @@ class PackageManagerService extends IPackageManager.Stub { File installDir; String codeFileName; String resourceFileName; + String libraryPath; boolean created = false; FileInstallArgs(InstallParams params) { @@ -5171,21 +4941,22 @@ class PackageManagerService extends IPackageManager.Stub { params.flags, params.installerPackageName); } - FileInstallArgs(String fullCodePath, String fullResourcePath) { + FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { super(null, null, 0, null); File codeFile = new File(fullCodePath); installDir = codeFile.getParentFile(); codeFileName = fullCodePath; resourceFileName = fullResourcePath; + libraryPath = nativeLibraryPath; } - FileInstallArgs(Uri packageURI, String pkgName) { + FileInstallArgs(Uri packageURI, String pkgName, String dataDir) { super(packageURI, null, 0, null); - boolean fwdLocked = isFwdLocked(flags); - installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir; + installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; String apkName = getNextCodePath(null, pkgName, ".apk"); codeFileName = new File(installDir, apkName + ".apk").getPath(); resourceFileName = getResourcePathFromCodePath(); + libraryPath = new File(dataDir, LIB_DIR_NAME).getPath(); } boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { @@ -5197,8 +4968,7 @@ class PackageManagerService extends IPackageManager.Stub { } void createCopyFile() { - boolean fwdLocked = isFwdLocked(flags); - installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir; + installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; codeFileName = createTempPackageFile(installDir).getPath(); resourceFileName = getResourcePathFromCodePath(); created = true; @@ -5226,8 +4996,7 @@ class PackageManagerService extends IPackageManager.Stub { } ParcelFileDescriptor out = null; try { - out = ParcelFileDescriptor.open(codeFile, - ParcelFileDescriptor.MODE_READ_WRITE); + out = ParcelFileDescriptor.open(codeFile, ParcelFileDescriptor.MODE_READ_WRITE); } catch (FileNotFoundException e) { Slog.e(TAG, "Failed to create file descritpor for : " + codeFileName); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; @@ -5241,6 +5010,11 @@ class PackageManagerService extends IPackageManager.Stub { } finally { try { if (out != null) out.close(); } catch (IOException e) {} } + + if (!temp) { + NativeLibraryHelper.copyNativeBinariesLI(codeFile, new File(libraryPath)); + } + return ret; } @@ -5296,6 +5070,11 @@ class PackageManagerService extends IPackageManager.Stub { } } + @Override + String getNativeLibraryPath() { + return libraryPath; + } + private boolean cleanUp() { boolean ret = true; String sourceDir = getCodePath(); @@ -5332,11 +5111,14 @@ class PackageManagerService extends IPackageManager.Stub { // we don't consider this to be a failure of the core package deletion } } + if (libraryPath != null) { + removeNativeBinariesLI(new File(libraryPath)); + } } private boolean setPermissions() { // TODO Do this in a more elegant way later on. for now just a hack - if (!isFwdLocked(flags)) { + if (!isFwdLocked()) { final int filePermissions = FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP |FileUtils.S_IROTH; @@ -5354,35 +5136,42 @@ class PackageManagerService extends IPackageManager.Stub { } boolean doPostDeleteLI(boolean delete) { + // XXX err, shouldn't we respect the delete flag? cleanUpResourcesLI(); return true; } + + private boolean isFwdLocked() { + return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; + } } class SdInstallArgs extends InstallArgs { - String cid; - String cachePath; static final String RES_FILE_NAME = "pkg.apk"; + String cid; + String packagePath; + String libraryPath; + SdInstallArgs(InstallParams params) { super(params.packageURI, params.observer, params.flags, params.installerPackageName); } - SdInstallArgs(String fullCodePath, String fullResourcePath) { + SdInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { super(null, null, PackageManager.INSTALL_EXTERNAL, null); // Extract cid from fullCodePath int eidx = fullCodePath.lastIndexOf("/"); String subStr1 = fullCodePath.substring(0, eidx); int sidx = subStr1.lastIndexOf("/"); cid = subStr1.substring(sidx+1, eidx); - cachePath = subStr1; + setCachePath(subStr1); } SdInstallArgs(String cid) { super(null, null, PackageManager.INSTALL_EXTERNAL, null); this.cid = cid; - cachePath = PackageHelper.getSdDir(cid); + setCachePath(PackageHelper.getSdDir(cid)); } SdInstallArgs(Uri packageURI, String cid) { @@ -5402,21 +5191,30 @@ class PackageManagerService extends IPackageManager.Stub { if (temp) { createCopyFile(); } - cachePath = imcs.copyResourceToContainer( + String newCachePath = imcs.copyResourceToContainer( packageURI, cid, getEncryptKey(), RES_FILE_NAME); - return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR : - PackageManager.INSTALL_SUCCEEDED; + if (newCachePath != null) { + setCachePath(newCachePath); + return PackageManager.INSTALL_SUCCEEDED; + } else { + return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; + } } @Override String getCodePath() { - return cachePath + "/" + RES_FILE_NAME; + return packagePath; } @Override String getResourcePath() { - return cachePath + "/" + RES_FILE_NAME; + return packagePath; + } + + @Override + String getNativeLibraryPath() { + return libraryPath; } int doPreInstall(int status) { @@ -5426,8 +5224,11 @@ class PackageManagerService extends IPackageManager.Stub { } else { boolean mounted = PackageHelper.isContainerMounted(cid); if (!mounted) { - cachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), Process.SYSTEM_UID); - if (cachePath == null) { + String newCachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), + Process.SYSTEM_UID); + if (newCachePath != null) { + setCachePath(newCachePath); + } else { return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; } } @@ -5473,13 +5274,19 @@ class PackageManagerService extends IPackageManager.Stub { return false; } Log.i(TAG, "Succesfully renamed " + cid + - " at path: " + cachePath + " to " + newCacheId + + " to " + newCacheId + " at new path: " + newCachePath); cid = newCacheId; - cachePath = newCachePath; + setCachePath(newCachePath); return true; } + private void setCachePath(String newCachePath) { + File cachePath = new File(newCachePath); + libraryPath = new File(cachePath, LIB_DIR_NAME).getPath(); + packagePath = new File(cachePath, RES_FILE_NAME).getPath(); + } + int doPostInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); @@ -5695,7 +5502,7 @@ class PackageManagerService extends IPackageManager.Stub { return; } } - boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res); } else { @@ -5855,7 +5662,7 @@ class PackageManagerService extends IPackageManager.Stub { !ps.codePathString.equals(oldPkgSetting.codePathString)) { int installFlags = 0; res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString, - oldPkgSetting.resourcePathString); + oldPkgSetting.resourcePathString, oldPkgSetting.nativeLibraryPathString); } } } @@ -6006,6 +5813,7 @@ class PackageManagerService extends IPackageManager.Stub { } // Set application objects path explicitly after the rename setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); + pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath(); if (replace) { replacePackageLI(pkg, parseFlags, scanMode, installerPackageName, res); @@ -6020,8 +5828,7 @@ class PackageManagerService extends IPackageManager.Stub { int retCode = 0; // TODO Gross hack but fix later. Ideally move this to be a post installation // check after alloting uid. - if ((newPackage.applicationInfo.flags - & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) { + if (isForwardLocked(newPackage)) { File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir); try { extractPublicFiles(newPackage, destResourceFile); @@ -6056,12 +5863,20 @@ class PackageManagerService extends IPackageManager.Stub { return PackageManager.INSTALL_SUCCEEDED; } - private boolean isForwardLocked(PackageParser.Package pkg) { - return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); + private static boolean isForwardLocked(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0; + } + + private static boolean isExternal(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + } + + private static boolean isSystemApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } - private boolean isExternal(PackageParser.Package pkg) { - return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + private static boolean isUpdatedSystemApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } private void extractPublicFiles(PackageParser.Package newPackage, @@ -6291,7 +6106,7 @@ class PackageManagerService extends IPackageManager.Stub { // we don't consider this to be a failure of the core package deletion } } else { - //for emulator + // for simulator PackageParser.Package pkg = mPackages.get(packageName); File dataDir = new File(pkg.applicationInfo.dataDir); dataDir.delete(); @@ -6374,7 +6189,7 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { // Reinstate the old system package mSettings.enableSystemPackageLP(p.packageName); - // Remove any native libraries. + // Remove any native libraries. XXX needed? removeNativeBinariesLI(p); } // Install the system package @@ -6410,12 +6225,10 @@ class PackageManagerService extends IPackageManager.Stub { // Delete application code and resources if (deleteCodeAndResources) { // TODO can pick up from PackageSettings as well - int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0) ? - PackageManager.INSTALL_EXTERNAL : 0; - installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ? - PackageManager.INSTALL_FORWARD_LOCK : 0; - outInfo.args = createInstallArgs(installFlags, - applicationInfo.sourceDir, applicationInfo.publicSourceDir); + int installFlags = isExternal(p) ? PackageManager.INSTALL_EXTERNAL : 0; + installFlags |= isForwardLocked(p) ? PackageManager.INSTALL_FORWARD_LOCK : 0; + outInfo.args = createInstallArgs(installFlags, applicationInfo.sourceDir, + applicationInfo.publicSourceDir, applicationInfo.nativeLibraryDir); } return true; } @@ -6460,7 +6273,7 @@ class PackageManagerService extends IPackageManager.Stub { return false; } boolean ret = false; - if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (isSystemApp(p)) { Log.i(TAG, "Removing system package:"+p.packageName); // When an updated system application is deleted we delete the existing resources as well and // fall back to existing code in system partition @@ -7160,10 +6973,14 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" pkg="); pw.println(ps.pkg); pw.print(" codePath="); pw.println(ps.codePathString); pw.print(" resourcePath="); pw.println(ps.resourcePathString); + pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); pw.print(" obbPath="); pw.println(ps.obbPathString); if (ps.pkg != null) { pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); + if (ps.pkg.mOperationPending) { + pw.println(" mOperationPending=true"); + } pw.print(" supportsScreens=["); boolean first = true; if ((ps.pkg.applicationInfo.flags & @@ -7211,9 +7028,6 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); pw.print(" installStatus="); pw.print(ps.installStatus); pw.print(" enabled="); pw.println(ps.enabled); - if (ps.pkg.mOperationPending) { - pw.println(" mOperationPending=true"); - } if (ps.disabledComponents.size() > 0) { pw.println(" disabledComponents:"); for (String s : ps.disabledComponents) { @@ -7730,6 +7544,7 @@ class PackageManagerService extends IPackageManager.Stub { String codePathString; File resourcePath; String resourcePathString; + String nativeLibraryPathString; String obbPathString; private long timeStamp; private String timeStampString = "0"; @@ -7769,7 +7584,7 @@ class PackageManagerService extends IPackageManager.Stub { this.resourcePathString = resourcePath.toString(); this.versionCode = pVersionCode; } - + public void setInstallerPackageName(String packageName) { installerPackageName = packageName; } @@ -8282,8 +8097,8 @@ class PackageManagerService extends IPackageManager.Stub { private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) { p.pkg = pkg; pkg.mSetEnabled = p.enabled; - String codePath = pkg.applicationInfo.sourceDir; - String resourcePath = pkg.applicationInfo.publicSourceDir; + final String codePath = pkg.applicationInfo.sourceDir; + final String resourcePath = pkg.applicationInfo.publicSourceDir; // Update code path if needed if (!codePath.equalsIgnoreCase(p.codePathString)) { Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName + @@ -8298,6 +8113,12 @@ class PackageManagerService extends IPackageManager.Stub { p.resourcePath = new File(resourcePath); p.resourcePathString = resourcePath; } + // Update the native library path if needed + final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir; + if (nativeLibraryPath != null + && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) { + p.nativeLibraryPathString = nativeLibraryPath; + } // Update version code if needed if (pkg.mVersionCode != p.versionCode) { p.versionCode = pkg.mVersionCode; @@ -8595,7 +8416,7 @@ class PackageManagerService extends IPackageManager.Stub { StringBuilder sb = new StringBuilder(); for (PackageSetting pkg : mPackages.values()) { ApplicationInfo ai = pkg.pkg.applicationInfo; - String dataPath = ai.dataDir; + String dataPath = ai.dataDir; boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; // Avoid any application that has a space in its path @@ -8668,6 +8489,9 @@ class PackageManagerService extends IPackageManager.Stub { if (!pkg.resourcePathString.equals(pkg.codePathString)) { serializer.attribute(null, "resourcePath", pkg.resourcePathString); } + if (pkg.nativeLibraryPathString != null) { + serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + } if (pkg.sharedUser == null) { serializer.attribute(null, "userId", Integer.toString(pkg.userId)); @@ -8707,6 +8531,9 @@ class PackageManagerService extends IPackageManager.Stub { if (!pkg.resourcePathString.equals(pkg.codePathString)) { serializer.attribute(null, "resourcePath", pkg.resourcePathString); } + if (pkg.nativeLibraryPathString != null) { + serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + } serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags)); serializer.attribute(null, "ts", pkg.getTimeStampStr()); @@ -9111,6 +8938,7 @@ class PackageManagerService extends IPackageManager.Stub { String sharedIdStr = null; String codePathStr = null; String resourcePathStr = null; + String nativeLibraryPathStr = null; String obbPathStr = null; String systemStr = null; String installerPackageName = null; @@ -9129,6 +8957,7 @@ class PackageManagerService extends IPackageManager.Stub { sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); codePathStr = parser.getAttributeValue(null, "codePath"); resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); obbPathStr = parser.getAttributeValue(null, "obbPath"); version = parser.getAttributeValue(null, "version"); if (version != null) { @@ -9227,6 +9056,7 @@ class PackageManagerService extends IPackageManager.Stub { if (packageSetting != null) { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; + packageSetting.nativeLibraryPathString = nativeLibraryPathStr; packageSetting.obbPathString = obbPathStr; final String enabledStr = parser.getAttributeValue(null, "enabled"); if (enabledStr != null) { @@ -9893,12 +9723,10 @@ class PackageManagerService extends IPackageManager.Stub { returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; } else { // Disable moving fwd locked apps and system packages - if (pkg.applicationInfo != null && - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (pkg.applicationInfo != null && isSystemApp(pkg)) { Slog.w(TAG, "Cannot move system application"); returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; - } else if (pkg.applicationInfo != null && - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) { + } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) { Slog.w(TAG, "Cannot move forward locked app."); returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED; } else if (pkg.mOperationPending) { @@ -9913,8 +9741,8 @@ class PackageManagerService extends IPackageManager.Stub { } else { newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; - currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ? - PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; + currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL + : PackageManager.INSTALL_INTERNAL; if (newFlags == currFlags) { Slog.w(TAG, "No move required. Trying to move to same location"); returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; @@ -9926,13 +9754,13 @@ class PackageManagerService extends IPackageManager.Stub { } } if (returnCode != PackageManager.MOVE_SUCCEEDED) { - processPendingMove(new MoveParams(null, observer, 0, packageName), returnCode); + processPendingMove(new MoveParams(null, observer, 0, packageName, null), returnCode); } else { Message msg = mHandler.obtainMessage(INIT_COPY); InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir, - pkg.applicationInfo.publicSourceDir); - MoveParams mp = new MoveParams(srcArgs, observer, newFlags, - packageName); + pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir); + MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName, + pkg.applicationInfo.dataDir); msg.obj = mp; mHandler.sendMessage(msg); } @@ -9950,7 +9778,7 @@ class PackageManagerService extends IPackageManager.Stub { ArrayList pkgList = null; synchronized (mPackages) { PackageParser.Package pkg = mPackages.get(mp.packageName); - if (pkg == null ) { + if (pkg == null) { Slog.w(TAG, " Package " + mp.packageName + " doesn't exist. Aborting move"); returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; @@ -9983,9 +9811,10 @@ class PackageManagerService extends IPackageManager.Stub { " Aborting move and returning error"); returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; } else { - String oldCodePath = pkg.mPath; - String newCodePath = mp.targetArgs.getCodePath(); - String newResPath = mp.targetArgs.getResourcePath(); + final String oldCodePath = pkg.mPath; + final String newCodePath = mp.targetArgs.getCodePath(); + final String newResPath = mp.targetArgs.getResourcePath(); + final String newNativePath = mp.targetArgs.getNativeLibraryPath(); pkg.mPath = newCodePath; // Move dex files around if (moveDexFilesLI(pkg) @@ -9998,6 +9827,7 @@ class PackageManagerService extends IPackageManager.Stub { pkg.mScanPath = newCodePath; pkg.applicationInfo.sourceDir = newCodePath; pkg.applicationInfo.publicSourceDir = newResPath; + pkg.applicationInfo.nativeLibraryDir = newNativePath; PackageSetting ps = (PackageSetting) pkg.mExtras; ps.codePath = new File(pkg.applicationInfo.sourceDir); ps.codePathString = ps.codePath.getPath(); -- cgit v1.1