DexClassLoader, reload Code fails with Signal 7

309 views Asked by At

I'm trying to build a plugin-System, where DexClassLoader is fetching code from other installed apks containing fragments(my plugins), and showing them in my host. This is working quite nice.

I also like to make the plugins hotswappable, this means I can change the code from a plugin, install it new and the host will notice and will load the new code. This also works, if I'm changing the code for the first time. (Although I thought it shouldn't, it seems I've got a wrong understanding of this code:

try {
 requiredClass = Class.forName(fullName);
 } catch(ClassNotFoundException e) {
 isLoaded = false;
 }

)

If i'm trying it a second time with the same plugin, the host shuts down at requiredClass = classLoader.loadClass(fullName); with something like

libc Fatal signal 7 (SIGBUS) at 0x596ed4d6 (code=2), thread 28814 (ctivityapp.host)

Does anybody has a deeper insight in the functionality of DexClassLoader and may tell me, what is happening here? I'm quite stuck at this.

Heres the full code of the method loading the foreign code:

     /**
     * takes the name of a package as String, and tries to load the code from the corresponding akp using DexclassLaoder. 
     * Checking if a package is a valid plugin must be done before calling this. 
     * The Plugin must contain a public class UI that extends Fragment and implements plugin as a starting point for loading
     * @param packageName The full name of the package, as String
     * @return the plugins object if loaded, null otherwise
     */
    private Plugin attachPluginToHost(String packageName) {
        try {
            Class<?> requiredClass = null;
            final ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName,0);
            final String apkPath = info.sourceDir;
            final File dexTemp = context.getDir("temp_folder", 0);
            final String fullName = packageName + ".UI";
            boolean isLoaded = true;
            // Check if class loaded
            try {
                requiredClass = Class.forName(fullName);
            } catch(ClassNotFoundException e) {
                isLoaded = false;
            }
            if (!isLoaded) {
                final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, context.getApplicationContext().getClassLoader());
                requiredClass = classLoader.loadClass(fullName);
            }
            if (null != requiredClass) {
               // Try to cast to required interface to ensure that it's can be cast
                final Plugin plugin = Plugin.class.cast(requiredClass.newInstance());
                installedPlugins.put(plugin.getName(), plugin);
                return plugin;
            }
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
    }

Many thanks in advance!

1

There are 1 answers

1
Kevin Gebhardt On BEST ANSWER

Not that it really matters (As nobody is actually viewing this), or that I even understand what's going on, but deleting the corresponding file of the plugin in dexTemp.getAbsolutePath() before reloading it solves the problem.

PS: Tumbleweed-Badge, YAY!