0

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.

Badger
  • 1
  • You can put a Java application into an app bundle: launcher and libs in "MacOS", jar files in Resources etc. You might have to write the launcher yourself, however, using the invocation interface. Don't know if there's a ready-made launcher for macOS out there or if the java executable from the JRE can be used – user2543253 Jul 01 '20 at 11:10
  • I understand that. But it means that you can't run the app from a standard Java IDE such as Netbeans. It starts the app using a standard CLI call of "java". – Badger Jul 01 '20 at 11:17
  • Go to _System Preferences_ - _Security & Privacy_ - select _Privacy_ tab - scroll down to _Developer Tools_ and add your IDE there. You can add Terminal, iTerm2, ... there as well. You should be able to run it locally even if it doesn't meet the system's security policy now. If you add a terminal, you can run basically _anything_ from it. – zrzka Jul 01 '20 at 12:55
  • @Badger yes, this is correct. But in development the JDK is under your control. You could give it access to the resources you need (maybe re-sign afterwards). Or you could use your private launcher, construct the classpath with the IDE's build folders and if you need to debug, attach a remote debugger. – user2543253 Jul 01 '20 at 13:39
  • @zrzka but for later use in production that's not an option – user2543253 Jul 01 '20 at 13:39
  • @Badger yes, not an option for production. My comment was because of _But it means that you can't run the app from a standard Java IDE such as Netbeans._ – zrzka Jul 01 '20 at 13:50

0 Answers0