summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityThread.java1
-rw-r--r--core/java/android/app/ApplicationLoaders.java10
-rw-r--r--core/java/android/app/LoadedApk.java8
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java20
-rw-r--r--core/java/android/content/pm/InstrumentationInfo.java12
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java296
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java16
7 files changed, 338 insertions, 25 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;