Make PackageManager unpack gdbserver binaries at installation time.
Native-debuggable packages contain a lib/<abi>/gdbserver executable.
This patch ensures that the package manager will copy it to the
proper location (/data/data/<appname>/lib) at installation time.
Note that such packages are marked with a new ApplicationInfo flag
named FLAG_NATIVE_DEBUGGABLE, to be used later by the Activity
Manager.
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index cafc804..1307972 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2855,9 +2855,8 @@
// room left on the data partition, or a ZipException if the package
// file is malformed.
//
- private int cachePackageSharedLibsForAbiLI( PackageParser.Package pkg,
- File dataPath, File scanFile, String cpuAbi)
- throws IOException, ZipException {
+ private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg,
+ File dataPath, File scanFile, String cpuAbi) throws IOException, ZipException {
File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
final String apkLib = "lib/";
final int apkLibLen = apkLib.length();
@@ -2935,7 +2934,7 @@
if (mInstaller == null) {
sharedLibraryDir.mkdir();
}
- cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
+ cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
sharedLibraryFile);
}
}
@@ -2948,6 +2947,54 @@
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 dataPath, File scanFile, String cpuAbi) throws IOException, ZipException {
+ File installGdbServerDir = new File(dataPath.getPath() + "/lib");
+ 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 (! installGdbServerFile.exists() ||
+ installGdbServerFile.length() != entry.getSize() ||
+ installGdbServerFile.lastModified() != entry.getTime()) {
+ 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.
//
@@ -2957,7 +3004,7 @@
//
private int cachePackageSharedLibsLI(PackageParser.Package pkg,
File dataPath, File scanFile) {
- final String cpuAbi = Build.CPU_ABI;
+ String cpuAbi = Build.CPU_ABI;
try {
int result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi);
@@ -2968,7 +3015,7 @@
//
// only scan the package twice in case of ABI mismatch
if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
+ final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
if (cpuAbi2 != null) {
result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi2);
}
@@ -2977,6 +3024,20 @@
Log.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, dataPath, scanFile, cpuAbi);
+ if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE;
+ }
}
} catch (ZipException e) {
Log.w(TAG, "Failed to extract data from package file", e);
@@ -2988,26 +3049,27 @@
return PackageManager.INSTALL_SUCCEEDED;
}
- private void cacheSharedLibLI(PackageParser.Package pkg,
+ private void cacheNativeBinaryLI(PackageParser.Package pkg,
ZipFile zipFile, ZipEntry entry,
- File sharedLibraryDir,
- File sharedLibraryFile) throws IOException {
+ File binaryDir,
+ File binaryFile) throws IOException {
InputStream inputStream = zipFile.getInputStream(entry);
try {
- File tempFile = File.createTempFile("tmp", "tmp", sharedLibraryDir);
+ File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
String tempFilePath = tempFile.getPath();
- // XXX package manager can't change owner, so the lib files for
+ // 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(sharedLibraryFile)) {
+ ! tempFile.renameTo(binaryFile)) {
// Failed to properly write file.
tempFile.delete();
- throw new IOException("Couldn't create cached shared lib "
- + sharedLibraryFile + " in " + sharedLibraryDir);
+ throw new IOException("Couldn't create cached binary "
+ + binaryFile + " in " + binaryDir);
}
} finally {
inputStream.close();