I develop a Java app in Netbeans on Mac OS X Catalina 10.5.15. It loads a Mac dynamic library (.dylib) over JNA. The library relies on the Mac's AVFoundation framework to connect to an iPhone over USB and get it's screen video.
In order to develop the app I run it from the command line (java -jar ) and from Netbeans. It means that the app is not a standard Mac app (.app). This approach worked fine until Java 13 and higher. It also broke with the most releases of Java 8, 11 and 12. For example, it works fine with Amazon Corretto up to version 1.8.0_242 but it crashes on the latest 1.8.0_252.
The app crashes for an exception in the native code when the library calls:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler<>]
The cause extracted from the crash report:
Crashed Thread: 31 Dispatch queue: com.apple.root.default-qos
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace TCC, Code 0x0
Thread 31 Crashed:: Dispatch queue: com.apple.root.default-qos
0 libsystem_kernel.dylib 0x00007fff6dc50ad6 __abort_with_payload + 10
1 libsystem_kernel.dylib 0x00007fff6dc523df abort_with_payload_wrapper_internal + 80
2 libsystem_kernel.dylib 0x00007fff6dc52411 abort_with_payload + 9
3 com.apple.TCC 0x00007fff6433459f __CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 163
4 com.apple.TCC 0x00007fff64332531 __TCCAccessRequest_block_invoke.114 + 500
The CRASHING_DUE_TO_PRIVACY_VIOLATION is the clue. I digged out that this is due to new privacy restrictions enforced by Mac OS Catalina 10.5. I need an Info.plist file and specify the NSCameraUsageDescription or NSMicrophoneUsageDescription keys in there as is documented in the AVCaptureDevice class spec.
Well, this is fine save that it makes development of Java + native code impossible. How can I debug and test a Java app calling such calls in Netbeans or from the command line?
I tried various tricks described on the web. I added entitlements to the library:
$ codesign -d -v -vvv --entitlements :- /Users/macmini/Library/Developer/Xcode/DerivedData/robot-ansbipjisxjlmcgmwwnmifcmjoqh/Build/Products/Debug/librobot.dylib
Executable=/Users/macmini/Library/Developer/Xcode/DerivedData/robot-ansbipjisxjlmcgmwwnmifcmjoqh/Build/Products/Debug/librobot.dylib
Identifier=librobot
Format=Mach-O thin (x86_64)
CodeDirectory v=20500 size=692 flags=0x10000(runtime) hashes=13+5 location=embedded
VersionPlatform=1
VersionMin=659200
VersionSDK=659204
Hash type=sha256 size=32
CandidateCDHash sha256=9e0cebcd55c641a0407c1a0a1ddf13060f0ca2f3
CandidateCDHashFull sha256=9e0cebcd55c641a0407c1a0a1ddf13060f0ca2f3992c2b1a5dac8125d4693939
Hash choices=sha256
CMSDigest=9e0cebcd55c641a0407c1a0a1ddf13060f0ca2f3992c2b1a5dac8125d4693939
CMSDigestType=2
Page size=4096
CDHash=9e0cebcd55c641a0407c1a0a1ddf13060f0ca2f3
Signature size=4736
Authority=Apple Development: John Doe (XXXXXXXX)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=1 Jul 2020 at 09:12:20
Info.plist=not bound
TeamIdentifier=XXXXXXXX
Runtime Version=10.15.4
Sealed Resources=none
Internal requirements count=1 size=168
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
</dict>
</plist>
It didn't help. Then I tried to create an Info.plist section in the dynamic library following this post. It didn't work either. The section in fact fails to create in the .dylib even though it builds fine in Xcode. When I run otool or codesign -d -v -vvv on the dylib it shows no plist. It appears that it's possible to add plist sections only to command line tools and not to libraries.
Does anyone have any other suggestions on how to make this work? I mean, I can package the Java app to the .app format for the final distribution but for development and integration purposes I need this to work from the command line. The only way I was able to figure out would be to convert the dylib into a properly configured Mac CLI application, start it from Java and communicate with it over a local TCP/IP port. Which is a hefty update to the project.