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

Verified Commit a830b5dd authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Dynamite: Use filters for class loader merging

parent a746e79b
Loading
Loading
Loading
Loading
+18 −21
Original line number Diff line number Diff line
@@ -23,14 +23,14 @@ import dalvik.system.PathClassLoader;

public class DynamiteContext extends ContextWrapper {
    private static final String TAG = "DynamiteContext";
    private String moduleId;
    private DynamiteModuleInfo moduleInfo;
    private Context originalContext;
    private Context gmsContext;
    private DynamiteContext appContext;

    public DynamiteContext(String moduleId, Context base, Context gmsContext, DynamiteContext appContext) {
    public DynamiteContext(DynamiteModuleInfo moduleInfo, Context base, Context gmsContext, DynamiteContext appContext) {
        super(base);
        this.moduleId = moduleId;
        this.moduleInfo = moduleInfo;
        this.originalContext = base;
        this.gmsContext = gmsContext;
        this.appContext = appContext;
@@ -38,7 +38,6 @@ public class DynamiteContext extends ContextWrapper {

    @Override
    public ClassLoader getClassLoader() {
        if (new DynamiteModuleInfo(moduleId).isMergeClassLoader()) {
        StringBuilder nativeLoaderDirs = new StringBuilder(gmsContext.getApplicationInfo().nativeLibraryDir);
        if (Build.VERSION.SDK_INT >= 23 && Process.is64Bit()) {
            for (String abi : Build.SUPPORTED_64_BIT_ABIS) {
@@ -51,10 +50,7 @@ public class DynamiteContext extends ContextWrapper {
        } else {
            nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(Build.CPU_ABI);
        }
            return new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), originalContext.getClassLoader());
        } else {
            return gmsContext.getClassLoader();
        }
        return new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), new FilteredClassLoader(originalContext.getClassLoader(), moduleInfo.getMergedClasses(), moduleInfo.getMergedPackages()));
    }

    @Override
@@ -75,17 +71,18 @@ public class DynamiteContext extends ContextWrapper {
    @RequiresApi(24)
    @Override
    public Context createDeviceProtectedStorageContext() {
        return new DynamiteContext(moduleId, originalContext.createDeviceProtectedStorageContext(), gmsContext.createDeviceProtectedStorageContext(), appContext);
        return new DynamiteContext(moduleInfo, originalContext.createDeviceProtectedStorageContext(), gmsContext.createDeviceProtectedStorageContext(), appContext);
    }

    public static DynamiteContext create(String moduleId, Context originalContext) {
        try {
            Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, new DynamiteModuleInfo(moduleId).getCreatePackageOptions());
            DynamiteModuleInfo moduleInfo = new DynamiteModuleInfo(moduleId);
            Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, 0);
            Context originalAppContext = originalContext.getApplicationContext();
            if (originalAppContext == null || originalAppContext == originalContext) {
                return new DynamiteContext(moduleId, originalContext, gmsContext, null);
                return new DynamiteContext(moduleInfo, originalContext, gmsContext, null);
            } else {
                return new DynamiteContext(moduleId, originalContext, gmsContext, new DynamiteContext(moduleId, originalAppContext, gmsContext, null));
                return new DynamiteContext(moduleInfo, originalContext, gmsContext, new DynamiteContext(moduleInfo, originalAppContext, gmsContext, null));
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.w(TAG, e);
+9 −6
Original line number Diff line number Diff line
@@ -5,6 +5,9 @@

package com.google.android.gms.chimera.container;

import java.util.Collection;
import java.util.Collections;

import static android.content.Context.CONTEXT_IGNORE_SECURITY;
import static android.content.Context.CONTEXT_INCLUDE_CODE;

@@ -33,19 +36,19 @@ public class DynamiteModuleInfo {
        }
    }

    public int getCreatePackageOptions() {
    public Collection<String> getMergedPackages() {
        try {
            return descriptor.getDeclaredField("CREATE_PACKAGE_OPTIONS").getInt(null);
            return (Collection<String>) descriptor.getDeclaredField("MERGED_PACKAGES").get(null);
        } catch (Exception e) {
            return CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY;
            return Collections.emptySet();
        }
    }

    public boolean isMergeClassLoader() {
    public Collection<String> getMergedClasses() {
        try {
            return descriptor.getDeclaredField("MERGE_CLASS_LOADER").getBoolean(null);
            return (Collection<String>) descriptor.getDeclaredField("MERGED_CLASSES").get(null);
        } catch (Exception e) {
            return false;
            return Collections.emptySet();
        }
    }
}
+56 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2021, microG Project Team
 * SPDX-License-Identifier: Apache-2.0
 */

package com.google.android.gms.chimera.container;

import android.util.Log;

import java.util.Collection;
import java.util.HashSet;

public class FilteredClassLoader extends ClassLoader {
    private static ClassLoader rootClassLoader;
    private final Collection<String> allowedClasses;
    private final Collection<String> allowedPackages;

    static {
        rootClassLoader = ClassLoader.getSystemClassLoader();
        if (rootClassLoader == null) {
            rootClassLoader = FilteredClassLoader.class.getClassLoader();
            while (rootClassLoader.getParent() != null) {
                rootClassLoader = rootClassLoader.getParent();
            }
        }
    }

    public FilteredClassLoader(ClassLoader parent, Collection<String> allowedClasses, Collection<String> allowedPackages) {
        super(parent);
        this.allowedClasses = new HashSet<>(allowedClasses);
        this.allowedPackages = new HashSet<>(allowedPackages);
    }

    private String getPackageName(String name) {
        int lastIndex = name.lastIndexOf(".");
        if (lastIndex <= 0) return "";
        return name.substring(0, lastIndex);
    }

    private String getClassName(String name) {
        int lastIndex = name.indexOf("$");
        if (lastIndex <= 0) return name;
        return name.substring(0, lastIndex);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if (name.startsWith("java.")) return rootClassLoader.loadClass(name);
        if (allowedClasses.contains(name) || allowedClasses.contains(getClassName(name)))
            return super.loadClass(name, resolve);
        if (allowedClasses.contains("!" + name) || allowedClasses.contains("!" + getClassName(name)))
            return rootClassLoader.loadClass(name);
        if (allowedPackages.contains(getPackageName(name))) return super.loadClass(name, resolve);
        return rootClassLoader.loadClass(name);
    }
}