2
votes

I have an android project developed with AndroidStudio and Gradle which embeds and starts a small OSGi project based on felix. To debug I use emulator for Nexus 5X with Android 8.0, API 26. I use declarative service and therefore my project bases on felix.main, felix.scr and felix.configadmin. All bundles are dexified. Installing the bundles works fine, but if I start the bundles by bundle.start() I get the following error message for felix.scr and felix.configadmin (felix.main and my own bundles work fine -> states are active):

08-03 13:58:00.880 19745-19745/android.cit.tu_berlin.de.helloandroid W/zygote: Skipping duplicate class check due to unrecognized classloader
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid E/OSGIService: catch exception while starting bundle:
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err: org.osgi.framework.BundleException: Activator start error in bundle org.apache.felix.configadmin [2].
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.Felix.activateBundle(Felix.java:2276)
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.Felix.startBundle(Felix.java:2144)
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984)
    08-03 13:58:00.881 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.cit.tu_berlin.de.helloandroid.OSGIService.startBundle(OSGIService.java:386)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.cit.tu_berlin.de.helloandroid.OSGIService.runSensorVisualisationPlugin(OSGIService.java:248)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.cit.tu_berlin.de.helloandroid.OSGIService.onStartCommand(OSGIService.java:158)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3539)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.app.ActivityThread.-wrap20(Unknown Source:0)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1698)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:105)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.os.Looper.loop(Looper.java:164)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6540)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err: Caused by: java.lang.UnsupportedOperationException: can't load this type of class file
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at java.lang.ClassLoader.defineClass(ClassLoader.java:591)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2370)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2154)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1542)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:79)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2018)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.BundleWiringImpl.getClassByDelegation(BundleWiringImpl.java:1415)
    08-03 13:58:00.882 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.Felix.createBundleActivator(Felix.java:4468)
    08-03 13:58:00.883 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:     at org.apache.felix.framework.Felix.activateBundle(Felix.java:2221)
    08-03 13:58:00.883 19745-19745/android.cit.tu_berlin.de.helloandroid W/System.err:  ... 15 more

The gradle script has the following statement for resolving dependencies to the felix jars:

provided fileTree(dir: 'src/main/assets/bundles/', include: ['*.jar'])
// for finding Felix.class
compile group: 'org.apache.felix', name: 'org.apache.felix.framework', version: '5.4.0'

And I needed to set the following property to felix to resolve missing requirement to osgi.ee (based on the answer of Christian Schneider in that post):

configMap.put(Constants.FRAMEWORK_SYSTEMCAPABILITIES, "osgi.ee; osgi.ee=\"JavaSE\";version:List=\"1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8\"");

I'm wondering if that error is related to that post particularly to the part 'Reference Library entry to the project Build Path' (based on the answer from Alec B. Plumb in that post) because I don't know why the first line of "my" error report says

W/zygote: Skipping duplicate class check due to unrecognized classloader

Why a duplicate class? Each lib is there one times and there are no further project settings or dependency links except in gradle.

I found a similar post and it is resolved by following Apache Felix tutorial steps. Nice, but I did the same and the error occurred furthermore.

I've tried a lot the last days, I read a lot the last days but what I found doesn't match my problem, I guess. Please help! And thanks a lot in advance!

Update 08.08.17:

I tried to find the original exception based on the answer of Balazs Zsoldos and that's the result: The exception is thrown in BundleWiringImpl.class in getClassByDelegation(String name):

public Class getClassByDelegation(String name) throws ClassNotFoundException {
        if(name != null && name.length() > 0 && name.charAt(0) == 91) {
            return Class.forName(name, false, this.getClassLoader());
        } else if(this.isFiltered(name)) {
            throw new ClassNotFoundException(name);
        } else {
            ClassLoader cl = this.getClassLoaderInternal();
            if(cl == null) {
                throw new ClassNotFoundException("Unable to load class \'" + name + "\' because the bundle wiring for " + this.m_revision.getSymbolicName() + " is no longer valid.");
            } else {
                return cl.loadClass(name);
            }
        }
    }

The last line (cl.loadClass(name)) throws the exception. For the sake of completeness here the values:

cl = org.apache.felix.configadmin
name = org.apache.felix.cm.impl.ConfigurationManager

Unfortunately I can not debug into that method, so I stopped there and set AndroidStudio to catch all exceptions. The next stop is caused by an exception thrown in DexFile.class

cause = java.lang.ClassNotFoundException: java.lang.Object
detailedMessage = Failed resolution of: Ljava/lang/Object

What the hell is that? Why in DexFile.class and WHY it's not possible to resolve the object class? I checked the dex-files and their entry name (maybe absolute path problem, Balazs Zsoldos mentioned) in the bundle jars. All right! There is no hidden addition. Can anybody help or did anybody have a similar issue and any idea how to solve?

Update 10.08.17

What I'm wondering is why only the felix bundles throw exceptions. Felix-Main bundle and my own work fine, they are in state active. And why is it possible that my own bundles based on declarative service are active even though the felix-scr bundle doesn't start (state is resolved). It seems felix-scr has not be in state active for resolving dependency to felix-scr. Anyway, why does the dexified felix libs fail and my own work? Please help, I'm desperate!

Update 11.08.2017

Today I tried my project to run and debug on a physical android device (Sony XPERIA Z2 with Android 4.4.4, API 19) and it works. All bundles are in state active. The last days I used the emulator for Nexus 5X with Android 8.0, API 26, so I edited my post to add that information. It seems to depend heavily on the device and/or the android version and the API. Crazy!

1

1 Answers

0
votes

Your biggest issue is that you cannot know the original exception due to a bug of Apache Felix: https://issues.apache.org/jira/browse/FELIX-5643

If there is an exception during Android based class loading

  • the exception is swallowed
  • Felix falls back to normal JDK class loading mechanism that throws the exception you see

We could solve the issue temporarily in two ways:

We did set a breakpoint to the beginning of BundleContextImpl.getDexFileClass(...) function in Android Studio and after it stopped, we did set Android dev studio to catch all exceptions. By doing that, we were able to find the original cause.

The first solution made us tired as we had to switch on and off the stop-at-exception feature. With many bundles where one is failing, it is hard to find the right one during debugging. Therefore, we simply copied out the content of BundleWiringImpl class into Android developer studio and changed it to log out the swallowed exception. By doing that, we were able to see the original exception in the log.

Btw.: The most annoying problem was the following. We dexified the jars as the tutorials said. However, the aapt command is that ugly, that if you specify the classes.dex file with an absolute URL, the entry of the ZIP will have the same name (including drive letter if you use windows). E.g.: The entry name of classes.dex in the zip is c:\classes.dex and no ZIP editor show the _c:_ part of its name. Therefore we listed the entry names of the ZIP/JAR in Java and to find out the real entry name.