Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1edab2b5 authored by David 'Digit' Turner's avatar David 'Digit' Turner
Browse files

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.
parent 8fdd45e1
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -233,6 +233,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
     */
    public static final int FLAG_ON_SDCARD = 1<<19;

    /**
     * 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<<20;

    /**
     * Flags associated with the application.  Any combination of
     * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
+76 −14
Original line number Diff line number Diff line
@@ -2856,8 +2856,7 @@ class PackageManagerService extends IPackageManager.Stub {
    // file is malformed.
    //
    private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg,
        File dataPath, File scanFile, String cpuAbi)
    throws IOException, ZipException {
        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();