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.
This commit is contained in:
David 'Digit' Turner
2010-01-21 15:15:23 -08:00
parent 8fdd45e1aa
commit 1edab2b551
2 changed files with 84 additions and 14 deletions

View File

@ -2855,9 +2855,8 @@ class PackageManagerService extends IPackageManager.Stub {
// 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 @@ class PackageManagerService extends IPackageManager.Stub {
if (mInstaller == null) {
sharedLibraryDir.mkdir();
}
cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
sharedLibraryFile);
}
}
@ -2948,6 +2947,54 @@ class PackageManagerService extends IPackageManager.Stub {
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 @@ class PackageManagerService extends IPackageManager.Stub {
//
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 @@ class PackageManagerService extends IPackageManager.Stub {
//
// 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 @@ class PackageManagerService extends IPackageManager.Stub {
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 @@ class PackageManagerService extends IPackageManager.Stub {
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();