GP-3623 - Extensions - Added an extension-specific class loader; moved ExtensionUtils to Generic

This commit is contained in:
dragonmacher 2023-11-21 11:18:28 -05:00
parent 80d92aa32f
commit 0a520b08bd
30 changed files with 1079 additions and 731 deletions

View file

@ -31,8 +31,23 @@ import ghidra.util.Msg;
*
*/
public class GhidraClassLoader extends URLClassLoader {
private static final String CP = "java.class.path";
/**
* When 'true', this property will trigger the system to put each Extension module's lib jar
* files into the {@link #CP_EXT} property.
*/
public static final String ENABLE_RESTRICTED_EXTENSIONS_PROPERTY =
"ghidra.extensions.classpath.restricted";
/**
* The classpath system property: {@code java.class.path}
*/
public static final String CP = "java.class.path";
/**
* The extensions classpath system property: {@code java.class.path.ext}
*/
public static final String CP_EXT = "java.class.path.ext";
/**
* This one-argument constructor is required for the JVM to successfully use this class loader
@ -45,7 +60,7 @@ public class GhidraClassLoader extends URLClassLoader {
}
@Override
public void addURL(URL url) {
public void addURL(URL url) {
super.addURL(url);
try {
System.setProperty(CP,

View file

@ -145,17 +145,36 @@ public class GhidraLauncher {
// First add Eclipse's module "bin" paths. If we didn't find any, assume Ghidra was
// compiled with Gradle, and add the module jars Gradle built.
addModuleBinPaths(classpathList, modules);
if (classpathList.isEmpty()) {
boolean gradleDevMode = classpathList.isEmpty();
if (gradleDevMode) {
// Add the module jars Gradle built.
// Note: this finds Extensions' jar files so there is no need to to call
// addExtensionJarPaths()
addModuleJarPaths(classpathList, modules);
}
else { /* Eclipse dev mode */
// Support loading pre-built, jar-based, non-repo extensions in Eclipse dev mode
addExtensionJarPaths(classpathList, modules, layout);
}
addExtensionJarPaths(classpathList, modules, layout);
// In development mode, jars do not live in module directories. Instead, each jar lives
// in an external, non-repo location, which is listed in build/libraryDependencies.txt.
addExternalJarPaths(classpathList, layout.getApplicationRootDirs());
}
else {
addPatchPaths(classpathList, layout.getPatchDir());
addModuleJarPaths(classpathList, modules);
}
//
// The framework may choose to handle extension class loading separately from all other
// class loading. In that case, we will separate the extension jar files from standard
// module jar files.
//
// (If the custom extension class loading is disabled, then the extensions will be put onto
// the standard classpath.)
setExtensionJarPaths(modules, layout, classpathList);
classpathList = orderClasspath(classpathList, modules);
return classpathList;
}
@ -202,6 +221,30 @@ public class GhidraLauncher {
dirs.forEach(d -> pathList.addAll(findJarsInDir(d)));
}
/**
* Initializes the Extension classpath system property, unless disabled.
* @param modules the known modules
* @param layout the application layout
* @param classpathList the standard classpath elements
*/
private static void setExtensionJarPaths(Map<String, GModule> modules,
GhidraApplicationLayout layout, List<String> classpathList) {
if (!Boolean.getBoolean(GhidraClassLoader.ENABLE_RESTRICTED_EXTENSIONS_PROPERTY)) {
// custom extension class loader is disabled; use normal classpath
return;
}
List<String> extClasspathList = new ArrayList<>();
addExtensionJarPaths(extClasspathList, modules, layout);
// Remove the extensions that were added before this method was called
classpathList.removeAll(extClasspathList);
String extCp = String.join(File.pathSeparator, extClasspathList);
System.setProperty(GhidraClassLoader.CP_EXT, extCp);
}
/**
* Add extension module lib jars to the given path list. (This only needed in dev mode to find
* any pre-built extensions that have been installed, since we already find extension module

View file

@ -17,6 +17,7 @@ package utility.application;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import generic.jar.ResourceFile;
import ghidra.framework.ApplicationProperties;
@ -30,7 +31,7 @@ public class DummyApplicationLayout extends ApplicationLayout {
/**
* Constructs a new dummy application layout object.
*
* @param name the application name
* @throws FileNotFoundException if there was a problem getting a user directory.
*/
public DummyApplicationLayout(String name) throws FileNotFoundException {
@ -48,5 +49,7 @@ public class DummyApplicationLayout extends ApplicationLayout {
// User directories
userTempDir = ApplicationUtilities.getDefaultUserTempDir(applicationProperties);
extensionInstallationDirs = Collections.emptyList();
}
}