JNI wrapper for NSSavePanel
Steve Hannah
steve at weblite.ca
Sun Oct 7 22:44:51 PDT 2012
> And one more long-shot: are you compiling your JNI library as ARC, or
> manual retain/release? I very much doubt that JNF will work correctly with
> compiler-generated ARC calls...but I could be surprised.
>
>
Your long shot was the money shot! ARC was turned on. After disabling it,
everything works as it should. Thank you so much for your help. It is
quite likely that I would have had to spend a month of Sundays solving this
problem if not for your help on this.
Best regards
Steve
> Regards,
> Mike Swingler
> Apple Inc.
>
> On Oct 7, 2012, at 8:37 PM, Steve Hannah <steve at weblite.ca> wrote:
>
> Another note: I just linked it to the JavaVM framework and
> JavaNativeFoundationFramework by right clicking on the "Other Frameworks"
> folder in the file tree of XCode, and selecting "Add Files to myproject",
> then proceeded to select:
> /System/Library/Frameworks/JavaVM
> and
> /System/Library/Frameworks/JavaVM/Frameworks/JavaNativeFoundation.
>
> This is my first JNI library, so it is possible I erred somewhere here.
> E.g. is it possible I linked against a framework for Java 6 when it needs
> to be for Java 7?
>
> -Steve
>
> On Sun, Oct 7, 2012 at 6:42 PM, Steve Hannah <steve at weblite.ca> wrote:
>
>> OK. I have made the following change to the method:
>>
>>
>> JNIEXPORT jstring JNICALL Java_ca_weblite_mactools_Sandbox_saveDialog
>>
>> (JNIEnv *env, jobject jthis, jstring title, jstring extension){
>>
>> JNF_COCOA_ENTER(<#env#>);
>>
>> return JNFNSToJavaString(env, @"/Users/shannah/Downloads/out2.pdf");
>>
>> JNF_COCOA_EXIT(env);
>>
>> return NULL;
>> }
>>
>> It still crashes. Here are some of the crash details.
>>
>> Process: JavaAppLauncher [13397]
>> Path:
>> /Users/USER/Documents/*/MyApp.app/Contents/MacOS/JavaAppLauncher
>> Identifier: ca.myidentifier
>> Version: 1.9.32 (1.9.32)
>> Code Type: X86-64 (Native)
>> Parent Process: launchd [140]
>> User ID: 501
>>
>> Date/Time: 2012-10-07 18:20:23.789 -0700
>> OS Version: Mac OS X 10.8.1 (12B19)
>> Report Version: 10
>>
>> Crashed Thread: 25 Java: Thread-2
>>
>> Exception Type: EXC_BAD_ACCESS (SIGABRT)
>> Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000020
>>
>> VM Regions Near 0x20:
>> -->
>> __TEXT 0000000103466000-000000010346a000 [ 16K]
>> r-x/rwx SM=COW
>> /Users/USER/Documents/*/MyApp.app/Contents/MacOS/JavaAppLauncher
>>
>> Application Specific Information:
>> abort() called
>>
>>
>> And the thread that crashed:
>>
>> Thread 25 Crashed:: Java: Thread-2
>> 0 libsystem_kernel.dylib 0x00007fff8a043212 __pthread_kill + 10
>> 1 libsystem_c.dylib 0x00007fff87e93b34 pthread_kill + 90
>> 2 libsystem_c.dylib 0x00007fff87ed7dfa abort + 143
>> 3 libjvm.dylib 0x0000000103a12a9f os::abort(bool) +
>> 25
>> 4 libjvm.dylib 0x0000000103aff35e
>> VMError::report_and_die() + 2306
>> 5 libjvm.dylib 0x0000000103a14193
>> JVM_handle_bsd_signal + 1073
>> 6 libsystem_c.dylib 0x00007fff87e8092a _sigtramp + 26
>> 7 libobjc.A.dylib 0x00007fff898d33ee objc_retain + 14
>> 8 ??? 0x0000000104267f90 0 + 4364599184
>> 9 ??? 0x000000010425c333 0 + 4364550963
>> 10 ??? 0x00000001042564f7 0 + 4364526839
>> 11 libjvm.dylib 0x00000001038ea083
>> JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*,
>> Thread*) + 557
>> 12 libjvm.dylib 0x00000001038e9e50
>> JavaCalls::call(JavaValue*, methodHandle, JavaCallArguments*, Thread*) + 40
>> 13 libjvm.dylib 0x0000000103a53062
>> Reflection::invoke(instanceKlassHandle, methodHandle, Handle, bool,
>> objArrayHandle, BasicType, objArrayHandle, bool, Thread*) + 2506
>> 14 libjvm.dylib 0x0000000103a534ba
>> Reflection::invoke_method(oopDesc*, Handle, objArrayHandle, Thread*) + 360
>> 15 libjvm.dylib 0x000000010391a99b JVM_InvokeMethod +
>> 352
>> 16 ??? 0x0000000104267f90 0 + 4364599184
>> 17 ??? 0x000000010425c333 0 + 4364550963
>> 18 ??? 0x000000010425c333 0 + 4364550963
>> 19 ??? 0x000000010425c9e1 0 + 4364552673
>> 20 ??? 0x000000010425c333 0 + 4364550963
>> 21 ??? 0x000000010425c333 0 + 4364550963
>> 22 ??? 0x000000010425c333 0 + 4364550963
>> 23 ??? 0x000000010425c333 0 + 4364550963
>> 24 ??? 0x000000010425c333 0 + 4364550963
>> 25 ??? 0x000000010425c333 0 + 4364550963
>> 26 ??? 0x000000010425c333 0 + 4364550963
>> 27 ??? 0x000000010425c333 0 + 4364550963
>> 28 ??? 0x000000010425c333 0 + 4364550963
>> 29 ??? 0x000000010425c333 0 + 4364550963
>> 30 ??? 0x000000010425c333 0 + 4364550963
>> 31 ??? 0x000000010425c333 0 + 4364550963
>> 32 ??? 0x000000010425c333 0 + 4364550963
>> 33 ??? 0x000000010425c333 0 + 4364550963
>> 34 ??? 0x000000010425c333 0 + 4364550963
>> 35 ??? 0x000000010425c333 0 + 4364550963
>> 36 ??? 0x000000010425c158 0 + 4364550488
>> 37 ??? 0x000000010425c158 0 + 4364550488
>> 38 ??? 0x000000010425c806 0 + 4364552198
>> 39 ??? 0x00000001042564f7 0 + 4364526839
>> 40 libjvm.dylib 0x00000001038ea083
>> JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*,
>> Thread*) + 557
>> 41 libjvm.dylib 0x00000001038ea560
>> JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*,
>> JavaCallArguments*, Thread*) + 256
>> 42 libjvm.dylib 0x00000001038ea69a
>> JavaCalls::call_virtual(JavaValue*, Handle, KlassHandle, Symbol*, Symbol*,
>> Thread*) + 74
>> 43 libjvm.dylib 0x000000010391d504
>> thread_entry(JavaThread*, Thread*) + 169
>> 44 libjvm.dylib 0x0000000103ad4f74
>> JavaThread::thread_main_inner() + 134
>> 45 libjvm.dylib 0x0000000103ad6413 JavaThread::run()
>> + 369
>> 46 libjvm.dylib 0x0000000103a12fc1
>> java_start(Thread*) + 173
>> 47 libsystem_c.dylib 0x00007fff87e92782 _pthread_start + 327
>> 48 libsystem_c.dylib 0x00007fff87e7f1c1 thread_start + 13
>>
>>
>>
>> I ran otool -L on the library to check that the JavaNativeFoundation was
>> being linked and it looks like it is. It's output is as follows:
>>
>> macbook-air-2:MacTools shannah$ otool -L libmactools.dylib
>> libmactools.dylib:
>> /usr/local/lib/JSandbox.dylib (compatibility version 1.0.0, current
>> version 1.0.0)
>> /System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/JavaNativeFoundation.framework/Versions/A/JavaNativeFoundation
>> (compatibility version 1.0.0, current version 1.0.0)
>> /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
>> (compatibility version 1.0.0, current version 19.0.0)
>> /System/Library/Frameworks/JavaVM.framework/Versions/A/JavaVM
>> (compatibility version 1.0.0, current version 1.0.0)
>> /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
>> (compatibility version 45.0.0, current version 1187.0.0)
>> /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
>> (compatibility version 300.0.0, current version 945.0.0)
>> /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version
>> 228.0.0)
>> /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version
>> 169.3.0)
>> /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
>> (compatibility version 150.0.0, current version 744.0.0)
>>
>>
>> Does this information provide any clues that I might be missing?
>>
>> Thanks for all your help so far.
>>
>> Best regards
>>
>> Steve
>>
>>
>> On Sun, Oct 7, 2012 at 3:05 PM, Steve Hannah <steve at weblite.ca> wrote:
>>
>>
>>
>>>
>>> This is not a valid C function based on the return type - in the case
>>>> where an error occurs, the return value of this function is undefined and
>>>> will likely be whatever garbage is left on the stack (isn't Xcode
>>>> warning/erroring about this like crazy???). You need a "return NULL;" at
>>>> the very end so that the JNI return value will be defined in the case where
>>>> you don't make it to the first return.
>>>>
>>>> Thanks for the tip, I'll add the null return and see if that helps.
>>> (No Xcode didn't complain... no warnings, no errors, "build succeeded").
>>>
>>>>
>>>> Are you sure the library is even getting built and loaded? Can you make
>>>> a plain JNI function next to this one that contains nothing but a simple
>>>> "fprintf(stderr, "test\n");" in it? Call that first, and see if the library
>>>> is even loaded.
>>>>
>>>> Yes. The library is getting built and loaded. I have 2 other JNI
>>> methods that are working properly (but only if I don't wrap them in
>>> JNF_COCOA_ENTER/EXIT). In my java logging I output the string result of
>>> another one of the methods just before calling this one and it outputs fine.
>>>
>>>
>>>> Given my inexperience with XCode, I suspect that it could be a problem
>>>> with the way I'm building/linking the JNI library. The fact that calls to
>>>> JNFNSToJavaString() work makes me thing that the JavaNativeFoundation is
>>>> correctly linked (?).
>>>>
>>>>
>>>> It may be getting hauled in by Java 7 itself, and not explicitly
>>>> linked. If you don't have the JavaNativeFounation.framework explicitly
>>>> linked in the target that builds your library, that would also cause the
>>>> compiler to infer that the JNF_COCOA_ENTER/EXIT macros are actually
>>>> functions, and treat them as undeclared/unlinked entities.
>>>>
>>>> Run otool -L on your library, and make sure the full path to
>>>> JavaNativeFoundation.framework is printed out. If it isn't, you are only
>>>> picking up the symbols inside of it by accident.
>>>>
>>>
>>> Thanks... I'll try that.
>>>
>>> Best regards
>>>
>>> Steve
>>>
>>>
>>>>
>>>> Regards,
>>>> Mike Swingler
>>>> Apple Inc.
>>>>
>>>> Any other suggestions or tips, much appreciated.
>>>>
>>>>
>>>> Best regards
>>>>
>>>> Steve
>>>>
>>>>
>>>>>> JNF_COCOA_ENTER/EXIT do more than just setup an autorelease pool -
>>>>>> they also catch ObjC exceptions and re-throw them as Java runtime
>>>>>> exceptions.
>>>>>>
>>>>>> Do you have the backtrace of where you are crashing when using
>>>>>> JNF_COCOA_ENTER/EXIT?
>>>>>>
>>>>> I do, but I'm having difficulty making heads or tails from it. I'm
>>>>> also struggling with getting logging information out on the Java side as
>>>>> I'm working on a Mountain Lion machine and I can't find where System.out
>>>>> and System.err are logged by default... and the sandbox is making it
>>>>> difficult for me to set a log location manually... (anything that runs or
>>>>> fails before or during the setting of a custom log location is not logged).
>>>>>
>>>>>
>>>>> I think (but I'm not certain) that this is the way it is now on Lion
>>>>> and Mountain Lion - output logged to stdout/stderr directly (including the
>>>>> JVM System.out/err) just goes to /dev/null unless you run the primary
>>>>> executable from a shell or some other parent process that gives it a TTY.
>>>>> Otherwise, the only thing that gets logged to the system console comes
>>>>> through ASL, like NSLog(). Of course, I may be completely off on this, but
>>>>> perhaps this is explaining what you are seeing.
>>>>>
>>>>> Also, are you doing anything special to run this JNI method on the
>>>>>> main AppKit thread (or are you using SWT)?
>>>>>
>>>>> Ah.. I hadn't thought of that, but yes. I'm overriding the
>>>>> java.awt.FileDialog class's setVisible() method to display this as a modal
>>>>> dialog.
>>>>>
>>>>>
>>>>>> If not, you may want to use +[JNFRunLoop
>>>>>> performOnMainThreadWaiting:withBlock:], which will block the current
>>>>>> thread, run your block on the main thread (safe for AppKit), and then
>>>>>> continue execution of your Java thread when the block returns.
>>>>>>
>>>>>
>>>>> I'll give this a shot.
>>>>>
>>>>> Thanks for the suggestions.
>>>>>
>>>>>
>>>>> No problem. Please do always think of the threading considerations
>>>>> when writing JNI. We try to let you not worry about exceptions and
>>>>> autorelease pools if you use JNF, but threading is still something you have
>>>>> to think through when you get JNI and Cocoa tangled together.
>>>>>
>>>>> Best of luck,
>>>>> Mike Swingler
>>>>> Apple Inc.
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Steve Hannah
>>>> Web Lite Solutions Corp.
>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>> Steve Hannah
>>> Web Lite Solutions Corp.
>>>
>>>
>>
>>
>> --
>> Steve Hannah
>> Web Lite Solutions Corp.
>>
>>
>
>
> --
> Steve Hannah
> Web Lite Solutions Corp.
>
>
>
--
Steve Hannah
Web Lite Solutions Corp.
More information about the macosx-port-dev
mailing list