Archinamon / android-gradle-aspectj

gradle plug-in adding supports of AspectJ into Android project
Apache License 2.0
363 stars 58 forks source link

com.archinamon.aspectj-ext and includeAllJars app crashing on startup #51

Closed siniy123 closed 7 years ago

siniy123 commented 7 years ago

When running attached sample app with com.archinamon.aspectj-ext and includeAllJars = true the app is crashing on startup in simulator (Genymotion API 23) with the error below.

When running with com.archinamon.aspectj-ext plug-in disabled the app starts just fine.

Please note that application main activity is not implemented in main app modules, but in in the lib used by the library. Maybe it is related to multiDex treatment.

Please also find attached small Android Studio project with 2 modules app that simulates the issue.

test-project-for-archinamon.zip

--------- beginning of crash 05-20 04:20:54.191 23882-23882/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.mycompany.myapp.non.store.id, PID: 23882 java.lang.RuntimeException: Unable to instantiate application com.mycompany.myapp.MyAppMyCompanyApplication: java.lang.ClassNotFoundException: Didn't find class "com.mycompany.myapp.MyAppMyCompanyApplication" on path: DexPathList[[zip file "/data/app/com.mycompany.myapp.non.store.id-2/base.apk"],nativeLibraryDirectories=[/data/app/com.mycompany.myapp.non.store.id-2/lib/x86, /vendor/lib, /system/lib]] at android.app.LoadedApk.makeApplication(LoadedApk.java:578) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4680) at android.app.ActivityThread.-wrap1(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.ClassNotFoundException: Didn't find class "com.mycompany.myapp.MyAppMyCompanyApplication" on path: DexPathList[[zip file "/data/app/com.mycompany.myapp.non.store.id-2/base.apk"],nativeLibraryDirectories=[/data/app/com.mycompany.myapp.non.store.id-2/lib/x86, /vendor/lib, /system/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:511) at java.lang.ClassLoader.loadClass(ClassLoader.java:469) at android.app.Instrumentation.newApplication(Instrumentation.java:981) at android.app.LoadedApk.makeApplication(LoadedApk.java:573) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4680)  at android.app.ActivityThread.-wrap1(ActivityThread.java)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:5417)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)  Suppressed: java.io.IOException: No original dex files found for dex location /data/app/com.mycompany.myapp.non.store.id-2/base.apk at dalvik.system.DexFile.openDexFileNative(Native Method) at dalvik.system.DexFile.openDexFile(DexFile.java:295) at dalvik.system.DexFile.<init>(DexFile.java:80) at dalvik.system.DexFile.<init>(DexFile.java:59) at dalvik.system.DexPathList.loadDexFile(DexPathList.java:279) at dalvik.system.DexPathList.makePathElements(DexPathList.java:248) at dalvik.system.DexPathList.<init>(DexPathList.java:120) at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48) at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:65) at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:58) at android.app.LoadedApk.getClassLoader(LoadedApk.java:376) at android.app.LoadedApk.makeApplication(LoadedApk.java:568) ... 9 more Suppressed: java.lang.ClassNotFoundException: com.mycompany.myapp.MyAppMyCompanyApplication at java.lang.Class.classForName(Native Method) at java.lang.BootClassLoader.findClass(ClassLoader.java:781) at java.lang.BootClassLoader.loadClass(ClassLoader.java:841) at java.lang.ClassLoader.loadClass(ClassLoader.java:504) ... 12 more Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

Archinamon commented 7 years ago

Thanks for the details! I'll take a look on it as soon as I have some free time. :)

Badya commented 7 years ago

@siniy123 if you have multidex enabled, i recommend cleaning every time before building again - it helps me to overcome this problem.

@Archinamon i have seen this behavior many times - the only idea i got to fastFix this - is to remove predicate and always clean output:

if (!transformInvocation.isIncremental) {
    outputProvider.deleteAll()
}

Another idea is hidden inside the power of TransformAPI - check for changes with good usage of Scopes/ReferencedScopes

Also i don't fully understand the reason to do mergeJars inside transformation

siniy123 commented 7 years ago

@Badya, it is reproducible even if I run ./gradlew clean assembleDebug. Is there something else I should do?

Archinamon commented 7 years ago

Also i don't fully understand the reason to do mergeJars inside transformation

There's damn magic inside android tools. Without mergeJars we're getting Multiple Dex files exception because android's MergeJars transform unable to combine multiple identical files — one from jar, another is an output of aspectj transform.

Archinamon commented 7 years ago

Is there something else I should do?

Yes. You have not to use includeAllJars just for fun. I'll explain why it's bad. AJC (aspectj compiler) grabs all the jars and project's outputs with .class files under -inpath parameter. That means the AJC tries to lookup aspect classes within ALL libraries (I mean jars and aars too) and your own code. Some of them may become corrupted or incompatible in raw with AJC post-processing tools because there's may be a unusual bytecode manipulations that will brake AJC. I'd recommend to not using includeAllJars at all :) If you need to cover the concrete library with you aspect — please, use the includeJar attribute to qualify exact list of libraries (jars or aars, or even subproject modules) by simple verbose name (you don't need to qualify the full name).

@siniy123 I'm looking your example. It's working fine simply removing includeAllJars attribute. test-project-for-archinamon.zip Here is a working sample aspect. :)

siniy123 commented 7 years ago

I would like to apply my aspects to all code and libraries including 3rd parties in my project. If I use includeJar to list my libraries that define aspects - they are only applied to java (compiled) classes and not applied to 3rd party jars/aar.

Archinamon commented 7 years ago

@siniy123 in case you wanna cover with aspects from 3rd party libraries into 3rd party libraries you may use includeJar to define WHAT libraries to weave and includeAspectsFromJar to define WHERE from ajc should take aspects (if they may come from another jar).

In case you wanna cover all code and all libraries with some aspects, you will have to determine what library breaks ajc yourself. :( It could be static analyse tool or any other. Anyway it's unpleasant work.

siniy123 commented 7 years ago

In case you wanna cover all code and all libraries with some aspects, you will have to determine what library breaks ajc yourself. :( It could be static analyse tool or any other. Anyway it's unpleasant work.

We did the exercise of excluding these libraries for our app community already, so we are ok with paying catchup with it. The original problem is not quite related since everything builds fine and just crashed on start-up.

Archinamon commented 7 years ago

The core problem I found is that ajc fails during build on some library. You may find log file in the root directory or in build/ajc-transform.log file. So dexing process doesn't have needed class files and this causes fail at startup.

siniy123 commented 7 years ago

@Archinamon , thank you for the lead. I noticed this, but other build tasks sailed through. In the end to make it start I had to upgrade to new instabug library and I also had to exclude the library pointed to by you from -inpath. Thanks, again.