在 Android 中嵌入 OSGi Felix 会导致 UnsupportedOperationException:无法加载此类 class 文件

Embed OSGi Felix in Android causes in UnsupportedOperationException: can't load this type of class file

我有一个使用 AndroidStudio 和 Gradle 开发的 android 项目,它嵌入并启动了一个基于 felix 的小型 OSGi 项目。为了调试,我使用 Nexus 5X 的模拟器,Android 8.0,API 26。我使用声明式服务,因此我的项目基于 felix.main、felix.scr 和 felix.configadmin .所有的捆绑包都是 dexified 的。安装捆绑包工作正常,但如果我通过 bundle.start() 启动捆绑包,我会收到以下关于 felix.scr 和 felix.configadmin 的错误消息(felix.main 和我自己的捆绑包工作正常-> 状态处于活动状态):

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.access0(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

gradle 脚本有以下语句用于解析对 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'

我需要将以下 属性 设置为 felix 以解决对 osgi.ee 的缺失要求(基于 Christian Schneider 在 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\"");

我想知道这个错误是否与 post particularly to the part 'Reference Library entry to the project Build Path' (based on the answer from Alec B. Plumb in that post) 有关,因为我不知道为什么 "my" 错误报告的第一行说

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

为什么要重复 class?每个库都存在一次,除了 gradle.

之外没有进一步的项目设置或依赖关系链接

我发现了一个类似的 post,它已按照 Apache Felix 教程步骤解决。很好,但我也这样做了,而且还发生了错误。

最近几天我尝试了很多,最近几天我读了很多书,但我想我发现的与我的问题不符。请帮忙!提前致谢!

更新 08.08.17:

我试图根据 Balazs Zsoldos 的回答找到原始异常,结果是: 在 getClassByDelegation(String name):

中 BundleWiringImpl.class 抛出异常
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);
            }
        }
    }

最后一行 (cl.loadClass(name)) 抛出异常。为了完整起见,这里的值:

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

不幸的是,我无法调试该方法,所以我停在那里并设置 AndroidStudio 以捕获所有异常。下一站是DexFile.class

抛出异常导致的
cause = java.lang.ClassNotFoundException: java.lang.Object
detailedMessage = Failed resolution of: Ljava/lang/Object

那是什么鬼东西?为什么在 DexFile.class 中以及为什么无法解析对象 class?我检查了 bundle jar 中的 dex 文件及其条目名称(可能是绝对路径问题,Balazs Zsoldos 提到)。好的!没有隐藏的添加。任何人都可以提供帮助或是否有人有类似的问题并且知道如何解决?

更新 10.08.17

我想知道为什么只有 felix 包会抛出异常。 Felix-Main 捆绑包和我自己的工作正常,它们处于活动状态。为什么即使 felix-scr 包没有启动(状态已解决),我自己基于声明式服务的包也可能处于活动状态。似乎 felix-scr 没有处于活动状态以解决对 felix-scr 的依赖。 无论如何,为什么 dexified felix 库失败而我自己的工作?请帮忙,我很绝望!

2017 年 8 月 11 日更新

今天我尝试了我的项目 运行 并在物理 android 设备上调试(Sony XPERIA Z2 with Android 4.4.4, API 19)并且它作品。所有捆绑包都处于活动状态。最后几天我使用 Nexus 5X 的模拟器 Android 8.0,API 26,所以我编辑了我的 post 以添加该信息。它似乎在很大程度上取决于设备 and/or android 版本和 API。疯了!

您最大的问题是由于 Apache Felix 的一个错误,您无法知道原始异常:https://issues.apache.org/jira/browse/FELIX-5643

如果在基于Android的class加载过程中出现异常

  • 异常被吞没
  • Felix 恢复正常JDK class 抛出异常的加载机制

我们可以通过两种方式暂时解决问题:

我们确实在 Android Studio 中 BundleContextImpl.getDexFileClass(...) 函数的开头设置了一个断点,在它停止后,我们确实设置了Android dev studio 捕获所有异常。通过这样做,我们能够找到最初的原因。

第一个解决方案让我们很累,因为我们不得不打开和关闭异常停止功能。由于有许多捆绑包其中一个失败,因此在调试期间很难找到正确的捆绑包。因此,我们干脆把BundleWiringImplclass的内容复制到Androiddeveloper studio中,改成log out swallowed exception。通过这样做,我们能够在日志中看到原始异常。

顺便说一句:最烦人的问题如下。正如教程所说,我们对罐子进行了 dexified。但是,aapt 命令太丑陋了,如果你用绝对 URL 指定 classes.dex 文件,ZIP 的条目将具有相同的名称(如果您使用 windows,则包括驱动器号)。例如:classes.dex 在 zip 中的条目名称是 c:\classes.dex 并且没有 ZIP 编辑器显示 _c:_ 其名称的一部分。因此我们在Java中列出了ZIP/JAR的条目名称,以找出真正的条目名称。