GP-6073 - FID - Implemented delayed DB loading to improve tool startup.

This commit is contained in:
dragonmacher
2025-10-27 15:47:57 -04:00
parent 25c2e8591e
commit 9b77c00442
3 changed files with 105 additions and 31 deletions

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -114,19 +114,25 @@ public class FidAnalyzer extends AbstractAnalyzer {
@Override
public boolean getDefaultEnablement(Program program) {
return service.canProcess(program.getLanguage());
// Loading Fid db files can be slow. For now, signal that we can analyze and check later.
return true;
//return service.canProcess(program.getLanguage());
}
@Override
public boolean canAnalyze(Program program) {
return service.canProcess(program.getLanguage());
// Loading Fid db files can be slow. For now, signal that we can analyze and check later.
return true;
//return service.canProcess(program.getLanguage());
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
if (!service.canProcess(program.getLanguage())) {
Msg.warn(this, "No FID Libraries apply for language " + program.getLanguageID());
// This can now happen, since we no longer check in canAnalyze()
Msg.debug(this, "No FID Libraries apply for language " + program.getLanguageID());
return false;
}

View File

@@ -27,14 +27,18 @@ import generic.util.Path;
import ghidra.framework.Application;
import ghidra.framework.preferences.Preferences;
import ghidra.program.model.lang.Language;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskMonitor;
/**
* Manages the set of FidFiles for the application. This uses the singleton pattern and
* all users of Fid databases must use this to get open Fid databases. This ensures that
* there is only one updateable Fid database open for any given FidFile.
* there is only one updatable Fid database open for any given FidFile.
*/
public class FidFileManager {
@@ -48,7 +52,7 @@ public class FidFileManager {
private WeakSet<ChangeListener> listeners;
/**
* Returns the singleton instance of the FidFileManager.
* {@return the singleton instance of the FidFileManager.}
*/
public static FidFileManager getInstance() {
if (THE_FID_FILE_MANAGER == null) {
@@ -59,14 +63,23 @@ public class FidFileManager {
private FidFileManager() {
listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet();
// findDeliveredFidFiles(); - too slow
// restoreFromPreferences();
}
private Set<FidFile> loadFidFiles() {
if (fidFiles == null) {
findDeliveredFidFiles();
restoreFromPreferences();
TaskLauncher.launchModal("Loading Fid Files", monitor -> {
fidFiles = new CopyOnWriteArraySet<>();
try {
findDeliveredFidFiles(monitor);
restoreFromPreferences(monitor);
}
catch (CancelledException ce) {
Msg.showWarn(this, null, "Fid Loading Cancelled", "User cancelled Fid Db " +
"loading. To load all Fid Db files, the tool must be restarted.");
}
});
}
return fidFiles;
@@ -74,7 +87,7 @@ public class FidFileManager {
/**
* Add user FidDb file
* @param file
* @param file the file
* @return FidFile or null if invalid
*/
public FidFile addUserFidFile(File file) {
@@ -105,7 +118,7 @@ public class FidFileManager {
}
/**
* Returns a list of all the FidFiles know to the application.
* {@return a list of all the FidFiles know to the application.}
*/
public List<FidFile> getFidFiles() {
loadFidFiles();
@@ -114,13 +127,30 @@ public class FidFileManager {
return files;
}
public boolean hasFidFiles() {
loadFidFiles();
return !fidFiles.isEmpty();
/**
* Triggers a load of the Fid db files, if not already loaded.
*/
public void load() {
if (fidFiles == null) {
loadFidFiles();
}
}
/**
* {@return true if Fid db files have been loaded and files have been found.}
*/
public boolean hasFidFiles() {
return fidFiles != null && !fidFiles.isEmpty();
}
/**
* {@return true if Fid db files have been loaded and user Fid files have been found.}
*/
public boolean hasUserFidFiles() {
loadFidFiles();
if (fidFiles == null) {
return false;
}
for (FidFile fidFile : fidFiles) {
if (!fidFile.isInstalled()) {
return true;
@@ -130,8 +160,15 @@ public class FidFileManager {
}
/**
* Returns a list of all the user added (non installation) Fid files. This will
* be files containing packed databases.
* {@return true if the Fid db files have been loaded.}
*/
public boolean hasLoadedFidFiles() {
return fidFiles != null;
}
/**
* {@return a list of all the user added (non installation) Fid files. This will
* be files containing packed databases.}
*/
public List<FidFile> getUserAddedFiles() {
loadFidFiles();
@@ -251,17 +288,20 @@ public class FidFileManager {
return list;
}
private void restoreFromPreferences() {
private void restoreFromPreferences(TaskMonitor monitor) throws CancelledException {
Set<File> userAddedFiles = getFilesFromPreference(USER_ADDED_FILES);
addUserFidFiles(userAddedFiles);
monitor.initialize(userAddedFiles.size(), "Adding user Fid files...");
doAddUserFidFiles(userAddedFiles, monitor);
Set<File> excludedFiles = getFilesFromPreference(INACTIVE_FID_FILES);
excludeFidFiles(excludedFiles);
monitor.initialize(excludedFiles.size(), "Removing inactive user Fid files...");
doExcludeFidFiles(excludedFiles, monitor);
}
private void addUserFidFiles(Set<File> userAddedFiles) {
loadFidFiles();
private void doAddUserFidFiles(Set<File> userAddedFiles, TaskMonitor monitor)
throws CancelledException {
for (File file : userAddedFiles) {
monitor.increment();
FidFile fidFile = new FidFile(this, file, false);
if (fidFile.isValidFile()) {
fidFiles.add(fidFile);
@@ -269,9 +309,10 @@ public class FidFileManager {
}
}
private void excludeFidFiles(Set<File> excludedFiles) {
loadFidFiles();
private void doExcludeFidFiles(Set<File> excludedFiles, TaskMonitor monitor)
throws CancelledException {
for (FidFile fidFile : fidFiles) {
monitor.increment();
if (excludedFiles.contains(fidFile.getFile())) {
fidFile.setActive(false);
}
@@ -296,11 +337,14 @@ public class FidFileManager {
return set;
}
private void findDeliveredFidFiles() {
fidFiles = new CopyOnWriteArraySet<>();
private void findDeliveredFidFiles(TaskMonitor monitor) throws CancelledException {
List<ResourceFile> foundFiles =
Application.findFilesByExtensionInApplication(FidFile.FID_RAW_DATABASE_FILE_EXTENSION);
monitor.initialize(foundFiles.size(), "Processing included Fid files...");
for (ResourceFile resourceFile : foundFiles) {
monitor.increment();
File file = resourceFile.getFile(true);
FidFile fidFile = new FidFile(this, file, true);
if (fidFile.isValidFile()) {

View File

@@ -94,7 +94,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
*/
private void createStandardActions() {
new ActionBuilder("Choose Active FidDbs", getName())
.enabledWhen(ac -> fidFileManager.hasFidFiles())
.enabledWhen(ac -> enabledForAnyFidFiles())
.onAction(ac -> chooseActiveFidDbs())
.menuPath(ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Choose active FidDbs...")
.menuGroup(MENU_GROUP_1, "1")
@@ -121,7 +121,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
.buildAndInstall(tool);
new ActionBuilder("Detach attached FidDb", getName())
.enabledWhen(ac -> fidFileManager.hasUserFidFiles())
.enabledWhen(ac -> enabledForUserFidFiles())
.onAction(ac -> removeFidFile())
.menuPath(ToolConstants.MENU_TOOLS, FUNCTION_ID_NAME, "Detach attached FidDb...")
.menuGroup(MENU_GROUP_1, "4")
@@ -130,8 +130,9 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
.buildAndInstall(tool);
new ActionBuilder("Populate FidDb from programs", getName())
.enabledWhen(ac -> fidFileManager.hasUserFidFiles())
.enabledWhen(ac -> enabledForUserFidFiles())
.onAction(ac -> {
fidFileManager.load();
PopulateFidDialog populateFidDialog = new PopulateFidDialog(tool, service);
tool.showDialog(populateFidDialog);
})
@@ -143,11 +144,30 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
.buildAndInstall(tool);
}
private boolean enabledForAnyFidFiles() {
if (!fidFileManager.hasLoadedFidFiles()) {
// We haven't loaded Fid files yet. Since we don't know if we can enable, return true
// so users can at least try to perform the action.
return true;
}
return fidFileManager.hasFidFiles();
}
private boolean enabledForUserFidFiles() {
if (!fidFileManager.hasLoadedFidFiles()) {
// We haven't loaded Fid files yet. Since we don't know if we can enable, return true
// so users can at least try to perform the action.
return true;
}
return fidFileManager.hasUserFidFiles();
}
/**
* Method to select which known FID databases are currently active
* during search.
*/
private synchronized void chooseActiveFidDbs() {
fidFileManager.load();
ActiveFidConfigureDialog dialog =
new ActiveFidConfigureDialog(fidFileManager.getFidFiles());
tool.showDialog(dialog);
@@ -159,6 +179,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
* extension (.fidb). If they don't, we will add it for them.
*/
private void createFidDb() {
fidFileManager.load();
File dbFile = askFile("Create new FidDb file", "Create");
if (dbFile == null) {
return;
@@ -186,6 +207,7 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
* Method to attach an already-created (but heretofore unknown) database.
*/
private void attachFidDb() {
fidFileManager.load();
File dbFile = askFile("Attach existing FidDb file", "Attach");
if (dbFile != null) {
fidFileManager.addUserFidFile(dbFile);
@@ -196,6 +218,8 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
* Method to "forget" about (close and stop trying to re-open next session) a FID database.
*/
private void removeFidFile() {
fidFileManager.load();
FidFile fidFile = askChoice("Choose FidDb to detach", "Please choose the FidDb to detach",
fidFileManager.getUserAddedFiles(), null);
if (fidFile != null) {