Search Unity

How to pass byte array from android java class to unity without copy?

Discussion in 'Android' started by watsonsong, Apr 5, 2022.

  1. watsonsong

    watsonsong

    Joined:
    May 13, 2015
    Posts:
    555
  2. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,736
    Unfortunately this is quite difficult to do in Unity of today. We plan to improve the interop in this area, but that's the future.
    Could you provide a bit more details on your scenario? What are you trying to pass and in which direction?
     
  3. watsonsong

    watsonsong

    Joined:
    May 13, 2015
    Posts:
    555
    I want to implement a 'Stream' on android. Convert the 'InputStream' on java into 'Stream' in c#. Because this is the only way to access the Streaming Assets on Android by 'AssetManager'.
    And I want to crypt the stream and send it to AssetBundle.LoadFromStreamAsync. I want to improve the IO performance, but I find these has a lot of memory copy to cross the language boundary: from java to c# and to c++.
     
  4. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,736
    You want to have encrypted asset bundle in streaming assets?
    UnityWebRequest can read streaming assets just fine. Use DownloadHandlerScript if you don't want load entire file to memory.

    I don't think it's worth going the Java <-> C# interop way. JNI is expensive, Java streams are also doubtful to be cheap and you can only get arrays from them, so copy is probably involved on Java side alone.
     
  5. watsonsong

    watsonsong

    Joined:
    May 13, 2015
    Posts:
    555
    I don't want to load the whole asset bundle into memory. If the asset bundle is trunk-base compressed, and LoadFromFile it will load the necessary object into the memory. When I use the LoadFromStream, if the managedBuffer is proper setup, I think this is the only way to encrypt asset bundle without load all in memory.

    In fact these has lower API AsyncReadManager can read the android streaming asset directly. But I hard to wrap it into C# Stream.
     
  6. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,736
    Well, efficient JNI won't be easy either, there is no direct bridge between Java stream and C# streams. The direct ByteBuffer is most efficient way of transferring bytes from Java, but you'd need some C++ glue and C# pointers, which gives you roughly the same as AsyncReadManager does.
    The simplest way to get a C# stream would be UnityWebRequest + DownloadHandlerScript with preallocated array, from which you then would copy data into stream.
    With AsyncReadManager you can probably do it more efficiently, but it's harder.
     
  7. watsonsong

    watsonsong

    Joined:
    May 13, 2015
    Posts:
    555
    Both UnityWebRequest and AsyncReadManager is an async API. And I think the LoadFromStream will invoke the sync version 'Read'.
    So I need use the async-API to implement a sync-API Read. The only way is both start the async load request and block to wait in the same 'Read' invoke. I don't think it a good idea.
     
    Last edited: Apr 6, 2022
  8. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,736
    Looks like LoadFromStreamAsync will call stream from other thread, so blocking will not block the main game.
     
  9. watsonsong

    watsonsong

    Joined:
    May 13, 2015
    Posts:
    555
    As I known, the AsyncReadManager just dispatch the sync File IO into another thread and wait. If the IO already on a single thread, is that also a waste?
     
  10. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,736
    I don't think it waits, it is only async. So you can submit commands from your stream and query their status.