Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2006-12-08 14:37:19 +0000
committerThomas Watson2006-12-08 14:37:19 +0000
commit666fdebf1b5dee3d2cfbe0abfd4dbd44a9da9172 (patch)
tree265b65efa53b01712f5df49a1dbf73d6c55e49df
parent9b49e85ec0d1c384833d554cfb07e3277738957d (diff)
downloadrt.equinox.framework-666fdebf1b5dee3d2cfbe0abfd4dbd44a9da9172.tar.gz
rt.equinox.framework-666fdebf1b5dee3d2cfbe0abfd4dbd44a9da9172.tar.xz
rt.equinox.framework-666fdebf1b5dee3d2cfbe0abfd4dbd44a9da9172.zip
Bug 156873 Refreshing bundle with native library causes a library loading exceptionR32x_v20061208
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java28
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java10
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java24
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java64
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java2
-rw-r--r--bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java3
6 files changed, 124 insertions, 7 deletions
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java
index 5cf202cc8..1bcd4bc72 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java
@@ -24,6 +24,7 @@ import org.eclipse.osgi.framework.adaptor.*;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.internal.protocol.bundleentry.Handler;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.*;
@@ -50,6 +51,8 @@ public class BaseData implements BundleData {
protected Dictionary manifest;
// This field is only used by PDE source lookup, and is set by a hook (bug 126517). It serves no purpose at runtime.
protected String fileName;
+ // This is only used to keep track of when the same native library is loaded more than once
+ protected Collection loadedNativeCode;
///////////////////// Begin values from Manifest /////////////////////
private String symbolicName;
@@ -118,11 +121,34 @@ public class BaseData implements BundleData {
for (int i = 0; i < hooks.length; i++) {
result = hooks[i].findLibrary(this, libname);
if (result != null)
- return result;
+ break;
}
+ // check to see if this library has been loaded by another class loader
+ if (result != null)
+ synchronized (this) {
+ if (loadedNativeCode == null)
+ loadedNativeCode = new ArrayList(1);
+ if (loadedNativeCode.contains(result)) {
+ // we must copy the library to a temp space to allow another class loader to load the library
+ String temp = copyToTempLibrary(result);
+ if (temp != null)
+ result = temp;
+ } else {
+ loadedNativeCode.add(result);
+ }
+ }
return result;
}
+ private String copyToTempLibrary(String result) {
+ try {
+ return adaptor.getStorage().copyToTempLibrary(this, result);
+ } catch (IOException e) {
+ adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null));
+ }
+ return null;
+ }
+
public void installNativeCode(String[] nativepaths) throws BundleException {
adaptor.getStorage().installNativeCode(this, nativepaths);
}
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java
index 0dee64150..e5cf0d8e7 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java
@@ -157,7 +157,11 @@ abstract public class BundleFile {
return mruIndex;
}
- protected static void setPermissions(File nested) {
+ /**
+ * Attempts to set the permissions of the file in a system dependant way.
+ * @param file the file to set the permissions on
+ */
+ public static void setPermissions(File file) {
String commandProp = FrameworkProperties.getProperty(PROP_SETPERMS_CMD);
if (commandProp == null)
return;
@@ -166,14 +170,14 @@ abstract public class BundleFile {
boolean foundFullPath = false;
for (int i = 0; i < temp.length; i++) {
if ("[fullpath]".equals(temp[i])) { //$NON-NLS-1$
- command.add(nested.getAbsolutePath());
+ command.add(file.getAbsolutePath());
foundFullPath = true;
}
else
command.add(temp[i]);
}
if (!foundFullPath)
- command.add(nested.getAbsolutePath());
+ command.add(file.getAbsolutePath());
try {
Runtime.getRuntime().exec((String[]) command.toArray(new String[command.size()])).waitFor();
} catch (Exception e) {
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java
index 2a511eef3..c9227ede3 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java
@@ -46,6 +46,8 @@ public class ClasspathManager {
private ClasspathEntry[] entries;
private BaseClassLoader classloader;
private FragmentClasspath[] fragments = emptyFragments;
+ // a colloction of String[2], each element is {"libname", "libpath"}
+ private Collection loadedLibraries = null;
/**
* Constructs a classpath manager for the given host base data, classpath and base class loader
@@ -530,4 +532,26 @@ public class ClasspathManager {
return classloader;
}
+ public String findLibrary(String libname) {
+ synchronized (this) {
+ if (loadedLibraries == null)
+ loadedLibraries = new ArrayList(1);
+ }
+ synchronized (loadedLibraries) {
+ // we assume that each classloader will load a small number of of libraries
+ // instead of wasting space with a map we iterate over our collection of found libraries
+ // each element is a String[2], each array is {"libname", "libpath"}
+ for (Iterator libs = loadedLibraries.iterator(); libs.hasNext();) {
+ String[] libNameResult = (String[]) libs.next();
+ if (libNameResult[0].equals(libname))
+ return libNameResult[1];
+ }
+
+ String result = classloader.getDelegate().findLibrary(libname);
+ if (result != null)
+ loadedLibraries.add(new String[] {libname, result});
+ return result;
+ }
+ }
+
}
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java
index c7aaa60c1..16aeb9b31 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java
@@ -47,6 +47,7 @@ public class BaseStorage {
private static final String PROP_BUNDLE_STORE = "osgi.bundlestore"; //$NON-NLS-1$
// The name of the bundle data directory
static final String DATA_DIR_NAME = "data"; //$NON-NLS-1$
+ static final String LIB_TEMP = "libtemp"; //$NON-NLS-1$
// System property used to determine whether State saver needs to be enabled
private static final String PROP_ENABLE_STATE_SAVER = "eclipse.enableStateSaver"; //$NON-NLS-1$
static final String BUNDLEFILE_NAME = "bundlefile"; //$NON-NLS-1$
@@ -71,6 +72,13 @@ public class BaseStorage {
* flag to indicate a framework extension is being updated
*/
public static final byte EXTENSION_UPDATED = 0x08;
+
+ /**
+ * the file name for the delete flag. If this file exists in one a directory
+ * under the bundle store area then it will be removed during the
+ * compact operation.
+ */
+ public static final String DELETE_FLAG = ".delete"; //$NON-NLS-1$
private static final String PERM_DATA_FILE = ".permdata"; //$NON-NLS-1$
private static final byte PERMDATA_VERSION = 1;
@@ -186,7 +194,7 @@ public class BaseStorage {
// if the file is a directory
if (!target.isDirectory())
continue;
- File delete = new File(target, ".delete"); //$NON-NLS-1$
+ File delete = new File(target, BaseStorage.DELETE_FLAG);
// and the directory is marked for delete
if (delete.exists()) {
// if rm fails to delete the directory and .delete was removed
@@ -1127,4 +1135,58 @@ public class BaseStorage {
return nextId++;
}
+ public String copyToTempLibrary(BaseData data, String absolutePath) throws IOException {
+ File storageRoot = getBundleStoreRoot();
+ File libTempDir = new File(storageRoot, LIB_TEMP);
+ // we assume the absolutePath is a File path
+ File realLib = new File(absolutePath);
+ String libName = realLib.getName();
+ // find a temp dir for the bundle data and the library;
+ File bundleTempDir = null;
+ File libTempFile = null;
+ // We need a somewhat predictable temp dir for the libraries of a given bundle;
+ // This is not strictly necessary but it does help scenarios where one native library loads another native library without using java.
+ // On some OSes this causes issues because the second library is cannot be found.
+ // This has been worked around by the bundles loading the libraries in a particular order (and setting some LIB_PATH env).
+ // The one catch is that the libraries need to be in the same directory and they must use their original lib names.
+ //
+ // This bit of code attempts to do that by using the bundle ID as an ID for the temp dir along with an incrementing ID
+ // in cases where the temp dir may already exist.
+ Long bundleID = new Long(data.getBundleID());
+ for (int i = 0; i < Integer.MAX_VALUE; i++) {
+ bundleTempDir = new File(libTempDir, bundleID.toString() + "_" + new Integer(i).toString()); //$NON-NLS-1$
+ libTempFile = new File(bundleTempDir, libName);
+ if (bundleTempDir.exists()) {
+ if (libTempFile.exists())
+ continue; // to to next temp file
+ break;
+ }
+ break;
+ }
+ if (!bundleTempDir.exists()) {
+ bundleTempDir.mkdirs();
+ bundleTempDir.deleteOnExit();
+ // This is just a safeguard incase the VM is terminated unexpectantly, it also looks like deleteOnExit cannot really work because
+ // the VM likely will still have a lock on the lib file at the time of VM exit.
+ File deleteFlag = new File(libTempDir, BaseStorage.DELETE_FLAG);
+ if (!deleteFlag.exists()) {
+ // need to create a delete flag to force removal the temp libraries
+ try {
+ FileOutputStream out = new FileOutputStream(deleteFlag);
+ out.close();
+ } catch (IOException e) {
+ // do nothing; that would mean we did not make the temp dir successfully
+ }
+ }
+ }
+ // copy the library file
+ InputStream in = new FileInputStream(realLib);
+ AdaptorUtil.readFile(in, libTempFile);
+ // set permissions if needed
+ BundleFile.setPermissions(libTempFile);
+ libTempFile.deleteOnExit(); // this probably will not work because the VM will probably have the lib locked at exit
+ // return the temporary path
+ return libTempFile.getAbsolutePath();
+ }
+
}
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java
index d3537ae1b..500afc19a 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java
@@ -238,7 +238,7 @@ public class BaseStorageHook implements StorageHook, AdaptorHook{
}
if (delete != null && delete.exists() && (postpone || !AdaptorUtil.rm(delete))) {
/* create .delete */
- FileOutputStream out = new FileOutputStream(new File(delete, ".delete")); //$NON-NLS-1$
+ FileOutputStream out = new FileOutputStream(new File(delete, BaseStorage.DELETE_FLAG));
out.close();
}
}
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java
index 8cce9985a..61770b076 100644
--- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java
+++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java
@@ -145,7 +145,8 @@ public class DefaultClassLoader extends ClassLoader implements BaseClassLoader {
* @return The URL of the resource or null if it does not exist.
*/
protected String findLibrary(String libname) {
- return delegate.findLibrary(libname);
+ // let the manager find the library for us
+ return manager.findLibrary(libname);
}
public ProtectionDomain getDomain() {

Back to the top