diff options
10 files changed, 613 insertions, 398 deletions
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<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>(); 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 <code>true</code> 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/<something>/lib<name>.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/<cpuAbi>/lib<name>.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<Pair<ZipEntry, String>> 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<? extends ZipEntry> 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/<something>/lib<name>.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<name>.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/<cpuAbi>/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<Pair<ZipEntry, String>> nativeFiles) throws IOException, ZipException { + final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER; + + Enumeration<? extends ZipEntry> 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/<cpuAbi>/lib<name>.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<Pair<ZipEntry, String>> 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<Pair<ZipEntry, String>> nativeFiles = new LinkedList<Pair<ZipEntry, String>>(); + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + + for (int i = 0; i < N; i++) { + final Pair<ZipEntry, String> 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<Pair<ZipEntry, String>> nativeFiles; + try { + zipFile = new ZipFile(codeFile); + + nativeFiles = new LinkedList<Pair<ZipEntry, String>>(); + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + for (int i = 0; i < N; i++) { + final Pair<ZipEntry, String> 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<ZipEntry, String> 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/<package name>/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/<cpuAbi>/lib<name>.so in the .apk - // and automatically copy them to /data/data/<appname>/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/<something>/lib<name>.so. - final int minEntryLen = apkLibLen + 2 + libPrefixLen + 1 + libSuffixLen; - - ZipFile zipFile = new ZipFile(scanFile); - Enumeration<ZipEntry> entries = - (Enumeration<ZipEntry>) 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/<something>/lib<name>.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<name>.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/<cpuAbi>/gdbserver and copy it to /data/data/<name>/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<ZipEntry> entries = - (Enumeration<ZipEntry>) 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/<cpuAbi>/lib<name>.so - // and copy them to /data/data/<appname>/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/<appname>/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/<abi> - // into /data/data/<appname>/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<String> 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(); |