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

Commit 1bea237a authored by Patrick Baumann's avatar Patrick Baumann
Browse files

In place split install native support

This change makes it possible for apps installed with the DONT_KILL flag
set to obtain access to newly installed native libraries while avoiding
double load of existing native libraries prior to the install when
loaded using System.loadLibrary.

Bug: 72047376
Test: manual - used sample app to verify availability of native libs
Change-Id: I331eaa48da1f8dee424584911317ec3fba92f873
parent 331a22e3
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -3723,6 +3723,7 @@ Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V
Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File;
Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File;
Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->addNativePath(Ljava/util/Collection;)V
Ldalvik/system/DexPathList;->definingContext:Ljava/lang/ClassLoader;
Ldalvik/system/DexPathList;->definingContext:Ljava/lang/ClassLoader;
Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->loadDexFile(Ljava/io/File;Ljava/io/File;Ljava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ldalvik/system/DexFile;
Ldalvik/system/DexPathList;->loadDexFile(Ljava/io/File;Ljava/io/File;Ljava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ldalvik/system/DexFile;
+13 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,8 @@ import com.android.internal.os.ClassLoaderFactory;


import dalvik.system.PathClassLoader;
import dalvik.system.PathClassLoader;


import java.util.Collection;

/** @hide */
/** @hide */
public class ApplicationLoaders {
public class ApplicationLoaders {
    public static ApplicationLoaders getDefault() {
    public static ApplicationLoaders getDefault() {
@@ -121,6 +123,17 @@ public class ApplicationLoaders {
        baseDexClassLoader.addDexPath(dexPath);
        baseDexClassLoader.addDexPath(dexPath);
    }
    }


    /**
     * @hide
     */
    void addNative(ClassLoader classLoader, Collection<String> libPaths) {
        if (!(classLoader instanceof PathClassLoader)) {
            throw new IllegalStateException("class loader is not a PathClassLoader");
        }
        final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
        baseDexClassLoader.addNativePath(libPaths);
    }

    private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>();
    private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>();


    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
+5 −0
Original line number Original line Diff line number Diff line
@@ -90,6 +90,7 @@ final class ServiceConnectionLeaked extends AndroidRuntimeException {
public final class LoadedApk {
public final class LoadedApk {
    static final String TAG = "LoadedApk";
    static final String TAG = "LoadedApk";
    static final boolean DEBUG = false;
    static final boolean DEBUG = false;
    private static final String PROPERTY_NAME_APPEND_NATIVE = "pi.append_native_lib_paths";


    private final ActivityThread mActivityThread;
    private final ActivityThread mActivityThread;
    final String mPackageName;
    final String mPackageName;
@@ -723,6 +724,10 @@ public final class LoadedApk {
            needToSetupJitProfiles = true;
            needToSetupJitProfiles = true;
        }
        }


        if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
            ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
        }

        if (addedPaths != null && addedPaths.size() > 0) {
        if (addedPaths != null && addedPaths.size() > 0) {
            final String add = TextUtils.join(File.pathSeparator, addedPaths);
            final String add = TextUtils.join(File.pathSeparator, addedPaths);
            ApplicationLoaders.getDefault().addPath(mClassLoader, add);
            ApplicationLoaders.getDefault().addPath(mClassLoader, add);
+4 −1
Original line number Original line Diff line number Diff line
@@ -282,7 +282,10 @@ public class NativeLibraryHelper {
        }
        }
    }
    }


    private static void createNativeLibrarySubdir(File path) throws IOException {
    /**
     * @hide
     */
    public static void createNativeLibrarySubdir(File path) throws IOException {
        if (!path.isDirectory()) {
        if (!path.isDirectory()) {
            path.delete();
            path.delete();


+75 −6
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.server.pm;
package com.android.server.pm;


import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA;
import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -74,6 +73,7 @@ import android.os.ParcelableException;
import android.os.Process;
import android.os.Process;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
import android.os.RevocableFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.ErrnoException;
@@ -111,9 +111,9 @@ import java.io.FileDescriptor;
import java.io.FileFilter;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicInteger;


@@ -154,6 +154,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    private static final String ATTR_NAME = "name";
    private static final String ATTR_NAME = "name";
    private static final String ATTR_INSTALL_REASON = "installRason";
    private static final String ATTR_INSTALL_REASON = "installRason";


    private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";

    // TODO: enforce INSTALL_ALLOW_TEST
    // TODO: enforce INSTALL_ALLOW_TEST
    // TODO: enforce INSTALL_ALLOW_DOWNGRADE
    // TODO: enforce INSTALL_ALLOW_DOWNGRADE


@@ -255,6 +257,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final List<String> mResolvedInstructionSets = new ArrayList<>();
    private final List<String> mResolvedInstructionSets = new ArrayList<>();
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
    @GuardedBy("mLock")
    private File mInheritedFilesBase;
    private File mInheritedFilesBase;


    private static final FileFilter sAddedFilter = new FileFilter() {
    private static final FileFilter sAddedFilter = new FileFilter() {
@@ -971,6 +975,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                        final File oatDir = new File(toDir, "oat");
                        final File oatDir = new File(toDir, "oat");
                        createOatDirs(mResolvedInstructionSets, oatDir);
                        createOatDirs(mResolvedInstructionSets, oatDir);
                    }
                    }
                    // pre-create lib dirs for linking if necessary
                    if (!mResolvedNativeLibPaths.isEmpty()) {
                        for (String libPath : mResolvedNativeLibPaths) {
                            // "/lib/arm64" -> ["lib", "arm64"]
                            final int splitIndex = libPath.lastIndexOf('/');
                            if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
                                Slog.e(TAG, "Skipping native library creation for linking due to "
                                        + "invalid path: " + libPath);
                                continue;
                            }
                            final String libDirPath = libPath.substring(1, splitIndex);
                            final File libDir = new File(toDir, libDirPath);
                            if (!libDir.exists()) {
                                NativeLibraryHelper.createNativeLibrarySubdir(libDir);
                            }
                            final String archDirPath = libPath.substring(splitIndex + 1);
                            NativeLibraryHelper.createNativeLibrarySubdir(
                                    new File(libDir, archDirPath));
                        }
                    }
                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
                } else {
                } else {
                    // TODO: this should delegate to DCS so the system process
                    // TODO: this should delegate to DCS so the system process
@@ -988,7 +1012,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        computeProgressLocked(true);
        computeProgressLocked(true);


        // Unpack native libraries
        // Unpack native libraries
        extractNativeLibraries(mResolvedStageDir, params.abiOverride);
        extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());


        // We've reached point of no return; call into PMS to install the stage.
        // We've reached point of no return; call into PMS to install the stage.
        // Regardless of success or failure we always destroy session.
        // Regardless of success or failure we always destroy session.
@@ -1027,6 +1051,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        }
        }
    }
    }


    /**
     * Returns true if the session should attempt to inherit any existing native libraries already
     * extracted at the current install location. This is necessary to prevent double loading of
     * native libraries already loaded by the running app.
     */
    private boolean mayInheritNativeLibs() {
        return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
                params.mode == SessionParams.MODE_INHERIT_EXISTING &&
                (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
    }

    /**
    /**
     * Validate install by confirming that all application packages are have
     * Validate install by confirming that all application packages are have
     * consistent package name, version code, and signing certificates.
     * consistent package name, version code, and signing certificates.
@@ -1249,6 +1284,38 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                    }
                    }
                }
                }
            }
            }

            // Inherit native libraries for DONT_KILL sessions.
            if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
                File[] libDirs = new File[]{
                        new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
                        new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
                for (File libDir : libDirs) {
                    if (!libDir.exists() || !libDir.isDirectory()) {
                        continue;
                    }
                    final List<File> libDirsToInherit = new LinkedList<>();
                    for (File archSubDir : libDir.listFiles()) {
                        if (!archSubDir.isDirectory()) {
                            continue;
                        }
                        String relLibPath;
                        try {
                            relLibPath = getRelativePath(archSubDir, packageInstallDir);
                        } catch (IOException e) {
                            Slog.e(TAG, "Skipping linking of native library directory!", e);
                            // shouldn't be possible, but let's avoid inheriting these to be safe
                            libDirsToInherit.clear();
                            break;
                        }
                        if (!mResolvedNativeLibPaths.contains(relLibPath)) {
                            mResolvedNativeLibPaths.add(relLibPath);
                        }
                        libDirsToInherit.addAll(Arrays.asList(archSubDir.listFiles()));
                    }
                    mResolvedInheritedFiles.addAll(libDirsToInherit);
                }
            }
        }
        }
    }
    }


@@ -1374,11 +1441,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
        Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
    }
    }


    private static void extractNativeLibraries(File packageDir, String abiOverride)
    private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
            throws PackageManagerException {
            throws PackageManagerException {
        // Always start from a clean slate
        final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
        final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
        if (!inherit) {
            // Start from a clean slate
            NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
            NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
        }


        NativeLibraryHelper.Handle handle = null;
        NativeLibraryHelper.Handle handle = null;
        try {
        try {