Adjust dynamite loader to support chimera modules with merged class loaders

This commit is contained in:
Marvin W 2021-05-14 23:52:21 +02:00
parent e42f68497f
commit 5d50ae375f
No known key found for this signature in database
GPG Key ID: 072E9235DB996F2A
4 changed files with 185 additions and 22 deletions

View File

@ -3,8 +3,12 @@ package com.google.android.gms.dynamite;
import com.google.android.gms.dynamic.IObjectWrapper;
interface IDynamiteLoader {
int getModuleVersion(IObjectWrapper context, String moduleId) = 0;
int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) = 2;
int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) = 0;
int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 2;
int getModuleVersion2NoCrashUtils(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 4;
IObjectWrapper createModuleContext(IObjectWrapper context, String moduleId, int minVersion) = 1;
}
IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 1;
IObjectWrapper createModuleContextNoCrashUtils(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 3;
int getIDynamiteLoaderVersion() = 5;
}

View File

@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.chimera.container;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
import android.util.Log;
import androidx.annotation.RequiresApi;
import org.microg.gms.common.Constants;
import java.io.File;
import dalvik.system.PathClassLoader;
public class DynamiteContext extends ContextWrapper {
private static final String TAG = "DynamiteContext";
private String moduleId;
private Context originalContext;
private Context gmsContext;
private DynamiteContext appContext;
public DynamiteContext(String moduleId, Context base, Context gmsContext, DynamiteContext appContext) {
super(base);
this.moduleId = moduleId;
this.originalContext = base;
this.gmsContext = gmsContext;
this.appContext = appContext;
}
@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) {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi);
}
} else if (Build.VERSION.SDK_INT >= 21) {
for (String abi : Build.SUPPORTED_32_BIT_ABIS) {
nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi);
}
} 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();
}
}
@Override
public String getPackageName() {
return gmsContext.getPackageName();
}
@Override
public ApplicationInfo getApplicationInfo() {
return gmsContext.getApplicationInfo();
}
@Override
public Context getApplicationContext() {
return appContext;
}
@RequiresApi(24)
@Override
public Context createDeviceProtectedStorageContext() {
return new DynamiteContext(moduleId, 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());
Context originalAppContext = originalContext.getApplicationContext();
if (originalAppContext == null || originalAppContext == originalContext) {
return new DynamiteContext(moduleId, originalContext, gmsContext, null);
} else {
return new DynamiteContext(moduleId, originalContext, gmsContext, new DynamiteContext(moduleId, originalAppContext, gmsContext, null));
}
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, e);
return null;
}
}
}

View File

@ -35,28 +35,41 @@ public class DynamiteLoaderImpl extends IDynamiteLoader.Stub {
@Override
public IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException {
// We don't have crash utils, so just forward
return createModuleContextNoCrashUtils(wrappedContext, moduleId, minVersion);
}
@Override
public IObjectWrapper createModuleContextNoCrashUtils(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException {
Log.d(TAG, "createModuleContext for " + moduleId + " at version " + minVersion);
final Context originalContext = (Context) ObjectWrapper.unwrap(wrappedContext);
return ObjectWrapper.wrap(DynamiteContext.create(moduleId, originalContext));
}
@Override
public int getIDynamiteLoaderVersion() throws RemoteException {
return 2;
}
@Override
public int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) throws RemoteException {
return getModuleVersion2(wrappedContext, moduleId, true);
}
@Override
public int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException {
// We don't have crash utils, so just forward
return getModuleVersion2NoCrashUtils(wrappedContext, moduleId, updateConfigIfRequired);
}
@Override
public int getModuleVersion2NoCrashUtils(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException {
final Context context = (Context) ObjectWrapper.unwrap(wrappedContext);
try {
return ObjectWrapper.wrap(new ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY)) {
@Override
public Context getApplicationContext() {
return context;
}
});
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "returning null instead", e);
return null;
if (context == null) {
Log.w(TAG, "Invalid client context");
return 0;
}
}
@Override
public int getModuleVersion(IObjectWrapper context, String moduleId) throws RemoteException {
return getModuleVersion2(context, moduleId, true);
}
@Override
public int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) throws RemoteException {
try {
return Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor").getDeclaredField("MODULE_VERSION").getInt(null);
} catch (Exception e) {

View File

@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.chimera.container;
import static android.content.Context.CONTEXT_IGNORE_SECURITY;
import static android.content.Context.CONTEXT_INCLUDE_CODE;
public class DynamiteModuleInfo {
private Class<?> descriptor;
private String moduleId;
public DynamiteModuleInfo(String moduleId) {
this.moduleId = moduleId;
try {
this.descriptor = Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor");
} catch (Exception e) {
// Ignore
}
}
public String getModuleId() {
return moduleId;
}
public int getVersion() {
try {
return descriptor.getDeclaredField("MODULE_VERSION").getInt(null);
} catch (Exception e) {
return 0;
}
}
public int getCreatePackageOptions() {
try {
return descriptor.getDeclaredField("CREATE_PACKAGE_OPTIONS").getInt(null);
} catch (Exception e) {
return CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY;
}
}
public boolean isMergeClassLoader() {
try {
return descriptor.getDeclaredField("MERGE_CLASS_LOADER").getBoolean(null);
} catch (Exception e) {
return false;
}
}
}