Update to jni 0.22.4 and gradle 9.3.1
This commit is contained in:
parent
135652a835
commit
194de1bb9c
131
Cargo.lock
generated
131
Cargo.lock
generated
@ -414,12 +414,6 @@ dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
@ -1804,27 +1798,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||
checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"cfg-if",
|
||||
"combine",
|
||||
"jni-sys 0.3.1",
|
||||
"jni-macros",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror 1.0.69",
|
||||
"simd_cesu8",
|
||||
"thiserror 2.0.18",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.1"
|
||||
name = "jni-macros"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
|
||||
checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
|
||||
dependencies = [
|
||||
"jni-sys 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"simd_cesu8",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3350,6 +3349,22 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||
|
||||
[[package]]
|
||||
name = "simd_cesu8"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
"simdutf8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "sketches-ddsketch"
|
||||
version = "0.3.1"
|
||||
@ -4408,22 +4423,13 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4432,7 +4438,7 @@ version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4444,35 +4450,20 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4493,36 +4484,18 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@ -4535,48 +4508,24 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
<h2>Overview of licenses:</h2>
|
||||
<ul class="licenses-overview">
|
||||
<li><a href="#MIT">MIT License</a> (188)</li>
|
||||
<li><a href="#MIT">MIT License</a> (185)</li>
|
||||
<li><a href="#AGPL-3.0-only">GNU Affero General Public License v3.0 only</a> (13)</li>
|
||||
<li><a href="#Apache-2.0">Apache License 2.0</a> (13)</li>
|
||||
<li><a href="#BSD-3-Clause">BSD 3-Clause "New" or "Revised" License</a> (4)</li>
|
||||
@ -1888,15 +1888,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
<h3 id="MIT">MIT License</h3>
|
||||
<h4>Used by:</h4>
|
||||
<ul class="license-used-by">
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows-sys 0.45.0</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows-sys 0.59.0</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows-sys 0.61.2</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows-targets 0.42.2</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows-targets 0.52.6</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows_aarch64_msvc 0.42.2</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows_aarch64_msvc 0.52.6</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows_x86_64_gnu 0.52.6</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows_x86_64_msvc 0.42.2</a></li>
|
||||
<li><a href="https://github.com/microsoft/windows-rs">windows_x86_64_msvc 0.52.6</a></li>
|
||||
</ul>
|
||||
<pre class="license-text"> MIT License
|
||||
@ -2359,7 +2355,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
<h3 id="MIT">MIT License</h3>
|
||||
<h4>Used by:</h4>
|
||||
<ul class="license-used-by">
|
||||
<li><a href="https://github.com/jni-rs/jni-sys">jni-sys 0.3.1</a></li>
|
||||
<li><a href="https://github.com/jni-rs/jni-sys">jni-sys 0.4.1</a></li>
|
||||
</ul>
|
||||
<pre class="license-text">Copyright (c) 2015 The rust-jni-sys Developers
|
||||
@ -3875,8 +3870,9 @@ SOFTWARE.
|
||||
<h3 id="MIT">MIT License (synthesized)</h3>
|
||||
<h4>Used by:</h4>
|
||||
<ul class="license-used-by">
|
||||
<li><a href="https://github.com/emk/cesu8-rs">cesu8 1.1.0</a></li>
|
||||
<li><a href="https://github.com/jni-rs/jni-rs">jni-macros 0.22.4</a></li>
|
||||
<li><a href="https://github.com/jni-rs/jni-sys">jni-sys-macros 0.4.1</a></li>
|
||||
<li><a href="https://github.com/jni-rs/jni-rs">jni 0.22.4</a></li>
|
||||
<li><a href="https://github.com/neon-bindings/neon">neon 1.1.1</a></li>
|
||||
<li><a href="https://github.com/madsmtm/objc2">objc2-core-foundation 0.3.2</a></li>
|
||||
<li><a href="https://github.com/madsmtm/objc2">objc2-io-kit 0.3.2</a></li>
|
||||
@ -3922,6 +3918,32 @@ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</li>
|
||||
<li class="license">
|
||||
<h3 id="MIT">MIT License</h3>
|
||||
<h4>Used by:</h4>
|
||||
<ul class="license-used-by">
|
||||
<li><a href="https://github.com/rusticstuff/simdutf8">simdutf8 0.1.5</a></li>
|
||||
</ul>
|
||||
<pre class="license-text">MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.</pre>
|
||||
</li>
|
||||
<li class="license">
|
||||
<h3 id="MIT">MIT License</h3>
|
||||
@ -3980,6 +4002,7 @@ SOFTWARE.
|
||||
<li><a href="https://github.com/serde-rs/serde">serde_core 1.0.228</a></li>
|
||||
<li><a href="https://github.com/serde-rs/serde">serde_derive 1.0.228</a></li>
|
||||
<li><a href="https://github.com/serde-rs/json">serde_json 1.0.149</a></li>
|
||||
<li><a href="https://github.com/seancroach/simd_cesu8">simd_cesu8 1.1.1</a></li>
|
||||
<li><a href="https://github.com/dtolnay/syn">syn 2.0.117</a></li>
|
||||
<li><a href="https://github.com/dtolnay/thiserror">thiserror-impl 1.0.69</a></li>
|
||||
<li><a href="https://github.com/dtolnay/thiserror">thiserror-impl 2.0.18</a></li>
|
||||
@ -4323,35 +4346,6 @@ furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</pre>
|
||||
</li>
|
||||
<li class="license">
|
||||
<h3 id="MIT">MIT License</h3>
|
||||
<h4>Used by:</h4>
|
||||
<ul class="license-used-by">
|
||||
<li><a href="https://github.com/jni-rs/jni-rs">jni 0.21.1</a></li>
|
||||
</ul>
|
||||
<pre class="license-text">The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Prevoty, Inc. and jni-rs contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
||||
@ -1783,7 +1783,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## windows-sys 0.45.0, windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.42.2, windows-targets 0.52.6, windows_aarch64_msvc 0.42.2, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.42.2, windows_x86_64_msvc 0.52.6
|
||||
## windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.52.6, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.52.6
|
||||
|
||||
```
|
||||
MIT License
|
||||
@ -2201,7 +2201,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## jni-sys 0.3.1, jni-sys 0.4.1
|
||||
## jni-sys 0.4.1
|
||||
|
||||
```
|
||||
Copyright (c) 2015 The rust-jni-sys Developers
|
||||
@ -3605,7 +3605,7 @@ SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## cesu8 1.1.0, jni-sys-macros 0.4.1, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2
|
||||
## jni-macros 0.22.4, jni-sys-macros 0.4.1, jni 0.22.4, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2
|
||||
|
||||
```
|
||||
MIT License
|
||||
@ -3629,6 +3629,30 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## simdutf8 0.1.5
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
## ident_case 1.0.1
|
||||
|
||||
```
|
||||
@ -3654,7 +3678,7 @@ SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21
|
||||
## curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, simd_cesu8 1.1.1, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21
|
||||
|
||||
```
|
||||
Permission is hereby granted, free of charge, to any
|
||||
@ -3977,33 +4001,6 @@ SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## jni 0.21.1
|
||||
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Prevoty, Inc. and jni-rs contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## same-file 1.0.6, winapi-util 0.1.11
|
||||
|
||||
```
|
||||
|
||||
@ -1868,7 +1868,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>windows-sys 0.45.0, windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.42.2, windows-targets 0.52.6, windows_aarch64_msvc 0.42.2, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.42.2, windows_x86_64_msvc 0.52.6</string>
|
||||
<string>windows-sys 0.59.0, windows-sys 0.61.2, windows-targets 0.52.6, windows_aarch64_msvc 0.52.6, windows_x86_64_gnu 0.52.6, windows_x86_64_msvc 0.52.6</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
@ -2340,7 +2340,7 @@ SOFTWARE.
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>jni-sys 0.3.1, jni-sys 0.4.1</string>
|
||||
<string>jni-sys 0.4.1</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
@ -3931,7 +3931,35 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>cesu8 1.1.0, jni-sys-macros 0.4.1, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2</string>
|
||||
<string>jni-macros 0.22.4, jni-sys-macros 0.4.1, jni 0.22.4, neon 1.1.1, objc2-core-foundation 0.3.2, objc2-io-kit 0.3.2, protobuf-parse 3.7.2, tonic-prost-build 0.14.5, windows-collections 0.2.0, windows-collections 0.3.2, windows-core 0.61.2, windows-core 0.62.2, windows-future 0.2.1, windows-future 0.3.2, windows-implement 0.60.2, windows-interface 0.59.3, windows-link 0.1.3, windows-link 0.2.1, windows-numerics 0.2.0, windows-numerics 0.3.1, windows-result 0.3.4, windows-result 0.4.1, windows-strings 0.4.2, windows-strings 0.5.1, windows-threading 0.1.0, windows-threading 0.2.1, windows 0.61.3, windows 0.62.2</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.</string>
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>simdutf8 0.1.5</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
@ -3993,7 +4021,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21</string>
|
||||
<string>curve25519-dalek-derive 0.1.1, anyhow 1.0.102, displaydoc 0.2.5, fastrand 2.4.1, home 0.5.12, itoa 1.0.18, linkme-impl 0.3.35, linkme 0.3.35, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, prettyplease 0.2.37, proc-macro-crate 3.5.0, proc-macro2 1.0.106, quote 1.0.45, rustix 0.38.44, rustix 1.1.4, rustversion 1.0.22, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.228, serde_core 1.0.228, serde_derive 1.0.228, serde_json 1.0.149, simd_cesu8 1.1.1, syn 2.0.117, thiserror-impl 1.0.69, thiserror-impl 2.0.18, thiserror 1.0.69, thiserror 2.0.18, unicode-ident 1.0.24, zmij 1.0.21</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
@ -4339,37 +4367,6 @@ SOFTWARE.
|
||||
<key>FooterText</key>
|
||||
<string>The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Prevoty, Inc. and jni-rs contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT License</string>
|
||||
<key>Title</key>
|
||||
<string>jni 0.21.1</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Andrew Gallant
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,7 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
15
gradlew
vendored
15
gradlew
vendored
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@ -84,7 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@ -112,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@ -170,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@ -203,15 +203,14 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
5
gradlew.bat
vendored
5
gradlew.bat
vendored
@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@ -68,11 +70,10 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id 'com.android.library' version '8.4.0'
|
||||
id 'com.android.library' version '9.1.1'
|
||||
id 'maven-publish'
|
||||
id 'signing'
|
||||
}
|
||||
@ -15,66 +15,73 @@ ext.release_jni_lib_dirs = project.hasProperty("releaseRingrtcLibDir") ? [releas
|
||||
ext.webrtc_jar = project.hasProperty("webrtcJar") ? webrtcJar : "libs/libwebrtc.jar"
|
||||
ext.asset_dir = project.hasProperty("assetDir") ? assetDir : "assets"
|
||||
|
||||
android {
|
||||
namespace 'org.signal.ringrtc'
|
||||
base {
|
||||
archivesName = "ringrtc-android"
|
||||
}
|
||||
|
||||
compileSdk 34
|
||||
android {
|
||||
namespace = 'org.signal.ringrtc'
|
||||
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk 21
|
||||
targetSdk 33
|
||||
versionName ringrtcVersion
|
||||
archivesBaseName = "ringrtc-android"
|
||||
minSdk = 21
|
||||
targetSdk = 33
|
||||
versionName = ringrtcVersion
|
||||
consumerProguardFiles "proguard-rules.pro"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
release {
|
||||
jniLibs.srcDirs = release_jni_lib_dirs
|
||||
java.srcDirs = ['api/']
|
||||
assets.srcDir asset_dir
|
||||
assets.srcDirs = [asset_dir]
|
||||
}
|
||||
debug {
|
||||
jniLibs.srcDirs = debug_jni_lib_dirs
|
||||
java.srcDirs = ['api/']
|
||||
assets.srcDir asset_dir
|
||||
assets.srcDirs = [asset_dir]
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
coreLibraryDesugaringEnabled = true
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
packaging {
|
||||
// Libraries are already stripped if necessary when linked.
|
||||
doNotStrip "**/*.so"
|
||||
jniLibs.keepDebugSymbols.add('**/*.so')
|
||||
}
|
||||
|
||||
publishing {
|
||||
singleVariant("release")
|
||||
singleVariant("release")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api files(webrtc_jar)
|
||||
api 'androidx.annotation:annotation:1.4.0'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6'
|
||||
androidTestImplementation "androidx.test:runner:1.4.0"
|
||||
androidTestImplementation "androidx.test:core:1.4.0"
|
||||
androidTestImplementation "org.mockito:mockito-android:5.1.1"
|
||||
api 'androidx.annotation:annotation:1.10.0'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||
androidTestImplementation "androidx.test:runner:1.5.0"
|
||||
androidTestImplementation "androidx.test:core:1.5.0"
|
||||
androidTestImplementation "org.mockito:mockito-android:5.12.0"
|
||||
}
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
source = android.sourceSets.release.java.sourceFiles
|
||||
classpath += files(android.bootClasspath)
|
||||
// There doesn't seem to be a convenient way to do this with just one variant.
|
||||
android.libraryVariants.all { v ->
|
||||
classpath += v.getCompileClasspath(null)
|
||||
tasks.register('javadoc', Javadoc) {
|
||||
source = fileTree(dir: 'api', include: '**/*.java')
|
||||
failOnError = false
|
||||
if (project.hasProperty('docsDir')) {
|
||||
destinationDir = new File(docsDir, 'javadoc')
|
||||
}
|
||||
// Normally this is set by the 'java' plugin, but that's not compatible with 'android-library'
|
||||
if (project.hasProperty("docsDir")) {
|
||||
destinationDir = new File(docsDir, "javadoc")
|
||||
}
|
||||
|
||||
androidComponents {
|
||||
onVariants(selector().withBuildType('release')) { variant ->
|
||||
tasks.named('javadoc').configure { task ->
|
||||
task.classpath = files(androidComponents.sdkComponents.bootClasspath) +
|
||||
project.configurations.named("${variant.name}CompileClasspath").get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +92,7 @@ afterEvaluate {
|
||||
from components.release
|
||||
|
||||
group = 'org.signal'
|
||||
artifactId = archivesBaseName
|
||||
artifactId = base.archivesName.get()
|
||||
version = ringrtcVersion
|
||||
|
||||
pom {
|
||||
@ -137,7 +144,7 @@ afterEvaluate {
|
||||
}
|
||||
|
||||
signing {
|
||||
required { isReleaseVersion && gradle.taskGraph.hasTask(getPath() + ":publish") }
|
||||
required = { isReleaseVersion && gradle.taskGraph.hasTask(getPath() + ":publish") }
|
||||
|
||||
def signingKeyId = findProperty("signingKeyId")
|
||||
def signingKey = findProperty("signingKey")
|
||||
@ -150,8 +157,8 @@ afterEvaluate {
|
||||
}
|
||||
}
|
||||
|
||||
task version {
|
||||
group 'Info'
|
||||
tasks.register('version') {
|
||||
group = 'Info'
|
||||
description = 'Prints the versions as read from the version config file.'
|
||||
doLast {
|
||||
println "RingRTC version: " + ringrtcVersion
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import org.signal.ringrtc.CallException;
|
||||
import org.signal.ringrtc.CallId;
|
||||
import org.signal.ringrtc.CallManager;
|
||||
import org.signal.ringrtc.GroupCall;
|
||||
|
||||
@ -18,8 +20,10 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class CallManagerTest extends CallTestBase {
|
||||
@ -147,4 +151,78 @@ public class CallManagerTest extends CallTestBase {
|
||||
callManager.receivedHttpResponse(requestId.getValue(), 404, new byte[] {});
|
||||
latch.await();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromEraIdRoundTrip() {
|
||||
CallId a1 = CallId.fromEra("mesozoic");
|
||||
CallId a2 = CallId.fromEra("mesozoic");
|
||||
CallId b = CallId.fromEra("cenozoic");
|
||||
errors.checkThat(a1, is(a2));
|
||||
errors.checkThat(a1, is(not(b)));
|
||||
errors.checkThat(a1.longValue(), is(not(0L)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAssetWithNoSourceThrows() throws Exception {
|
||||
CallManager callManager = CallManager.createCallManager(mock());
|
||||
try {
|
||||
callManager.addAsset("group", (byte[]) null);
|
||||
errors.addError(new AssertionError("expected CallException"));
|
||||
} catch (CallException ex) {
|
||||
errors.checkThat(ex.getMessage(),
|
||||
is("addAsset requires either a filePath or content"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAudioEnableNoActiveCallThrows() throws Exception {
|
||||
CallManager callManager = CallManager.createCallManager(mock());
|
||||
try {
|
||||
callManager.setAudioEnable(true);
|
||||
errors.addError(new AssertionError("expected CallException"));
|
||||
} catch (CallException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPeekWithManyMembers() throws Exception {
|
||||
final int GROUP_SIZE = 256;
|
||||
final int PARTICIPANTS = 100;
|
||||
CallManager.Observer observer = mock();
|
||||
CallManager callManager = CallManager.createCallManager(observer);
|
||||
|
||||
GroupCall.GroupMemberInfo[] memberInfos = new GroupCall.GroupMemberInfo[GROUP_SIZE];
|
||||
StringBuilder participants = new StringBuilder("[");
|
||||
for (int i = 0; i < GROUP_SIZE; i++) {
|
||||
byte[] opaque = fakeOpaqueUserId(i);
|
||||
memberInfos[i] = new GroupCall.GroupMemberInfo(UUID.nameUUIDFromBytes(opaque), opaque);
|
||||
if (i < PARTICIPANTS) {
|
||||
if (i > 0) participants.append(',');
|
||||
participants.append("{\"opaqueUserId\":\"")
|
||||
.append(sha256Hex(opaque))
|
||||
.append("\",\"demuxId\":")
|
||||
.append(32 * (i + 1))
|
||||
.append('}');
|
||||
}
|
||||
}
|
||||
participants.append(']');
|
||||
|
||||
String body = "{\"conferenceId\":\"jurassic\",\"maxDevices\":" + (PARTICIPANTS + 1)
|
||||
+ ",\"participants\":" + participants + ",\"pendingClients\":[]}";
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
callManager.peekGroupCall("sfu.example", new byte[] { 1, 2, 3 }, Arrays.asList(memberInfos), result -> {
|
||||
errors.checkThat(result.getEraId(), is("jurassic"));
|
||||
errors.checkThat(result.getDeviceCountIncludingPendingDevices(), is((long) PARTICIPANTS));
|
||||
errors.checkThat(result.getJoinedMembers().size(), is(PARTICIPANTS));
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
ArgumentCaptor<Long> requestId = ArgumentCaptor.forClass(Long.class);
|
||||
verify(observer).onSendHttpRequest(requestId.capture(), startsWith("sfu.example"), eq(CallManager.HttpMethod.GET), any(), any());
|
||||
|
||||
callManager.receivedHttpResponse(requestId.getValue(), 200, body.getBytes("UTF-8"));
|
||||
errors.checkThat("peek result lambda fired",
|
||||
latch.await(30, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ zkgroup = { git = "https://github.com/signalapp/libsignal", tag = "v0.89.2" }
|
||||
neon = { version = "1.1.1", optional = true, default-features = false, features = ["napi-6"] }
|
||||
|
||||
# Optional, needed to check Android-specific code when not targeting Android
|
||||
jni = { version = "0.21.1", optional = true, default-features = false }
|
||||
jni = { version = "0.22.4", optional = true, default-features = false }
|
||||
|
||||
# Optional, needed by the "http" feature
|
||||
ureq = { version = "3.1.4", optional = true }
|
||||
@ -138,7 +138,7 @@ path = "tests/outgoing.rs"
|
||||
required-features = ["sim"]
|
||||
|
||||
[target.'cfg(target_os="android")'.dependencies]
|
||||
jni = { version = "0.21.1", default-features = false }
|
||||
jni = { version = "0.22.4", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
uuid = { version = "1.19.0" }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,122 +3,106 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
EnvUnowned, jni_str,
|
||||
objects::{JByteArray, JClass, JObject, JString},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
android::{error, jni_util::*},
|
||||
core::util::try_scoped,
|
||||
lite::call_links::CallLinkRootKey,
|
||||
};
|
||||
use crate::{android::error::ThrowCallException, lite::call_links::CallLinkRootKey};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeParseKeyString<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
mut unowned_env: EnvUnowned<'local>,
|
||||
_class: JClass,
|
||||
string: JString,
|
||||
) -> JByteArray<'local> {
|
||||
try_scoped(|| {
|
||||
let string = env.get_string(&string)?;
|
||||
let key = CallLinkRootKey::try_from(Cow::from(&string).as_ref())?;
|
||||
Ok(env.byte_array_from_slice(key.as_slice())?)
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
error::throw_error(&mut env, e);
|
||||
JByteArray::default()
|
||||
})
|
||||
unowned_env
|
||||
.with_env(|env| -> Result<_> {
|
||||
let string = string.try_to_string(env)?;
|
||||
let key = CallLinkRootKey::try_from(string.as_str())?;
|
||||
Ok(env.byte_array_from_slice(key.as_slice())?)
|
||||
})
|
||||
.resolve::<ThrowCallException>()
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeValidateKeyBytes(
|
||||
mut env: JNIEnv,
|
||||
mut unowned_env: EnvUnowned,
|
||||
_class: JClass,
|
||||
bytes: JByteArray,
|
||||
) {
|
||||
try_scoped(|| {
|
||||
let bytes = env.convert_byte_array(bytes)?;
|
||||
let _ = CallLinkRootKey::try_from(bytes.as_slice())?;
|
||||
Ok(())
|
||||
})
|
||||
.unwrap_or_else(|e| error::throw_error(&mut env, e))
|
||||
unowned_env
|
||||
.with_env(|env| -> Result<()> {
|
||||
let bytes = env.convert_byte_array(bytes)?;
|
||||
let _ = CallLinkRootKey::try_from(bytes.as_slice())?;
|
||||
Ok(())
|
||||
})
|
||||
.resolve::<ThrowCallException>();
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_generate<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
mut unowned_env: EnvUnowned<'local>,
|
||||
_class: JClass,
|
||||
) -> JObject<'local> {
|
||||
try_scoped(|| {
|
||||
let key = CallLinkRootKey::generate(rand::rngs::OsRng);
|
||||
let bytes = env.byte_array_from_slice(key.as_slice())?;
|
||||
let object = jni_new_object(
|
||||
&mut env,
|
||||
jni_class_name!(org.signal.ringrtc.CallLinkRootKey),
|
||||
jni_args!((bytes => [byte]) -> void),
|
||||
)?;
|
||||
Ok(object)
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
error::throw_error(&mut env, e);
|
||||
JObject::default()
|
||||
})
|
||||
unowned_env
|
||||
.with_env(|env| -> Result<_> {
|
||||
let key = CallLinkRootKey::generate(rand::rngs::OsRng);
|
||||
let bytes = env.byte_array_from_slice(key.as_slice())?;
|
||||
let object = jni_new_object!(env, jni_str!("org/signal/ringrtc/CallLinkRootKey"), (
|
||||
bytes => [byte],
|
||||
))?;
|
||||
Ok(object)
|
||||
})
|
||||
.resolve::<ThrowCallException>()
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_generateAdminPasskey<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
mut unowned_env: EnvUnowned<'local>,
|
||||
_class: JClass,
|
||||
) -> JByteArray<'local> {
|
||||
try_scoped(|| {
|
||||
let passkey = CallLinkRootKey::generate_admin_passkey(rand::rngs::OsRng);
|
||||
Ok(env.byte_array_from_slice(&passkey)?)
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
error::throw_error(&mut env, e);
|
||||
JByteArray::default()
|
||||
})
|
||||
unowned_env
|
||||
.with_env(|env| -> Result<_> {
|
||||
let passkey = CallLinkRootKey::generate_admin_passkey(rand::rngs::OsRng);
|
||||
Ok(env.byte_array_from_slice(&passkey)?)
|
||||
})
|
||||
.resolve::<ThrowCallException>()
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeDeriveRoomId<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
mut unowned_env: EnvUnowned<'local>,
|
||||
_class: JClass,
|
||||
key_bytes: JByteArray,
|
||||
) -> JByteArray<'local> {
|
||||
try_scoped(|| {
|
||||
let key_bytes = env.convert_byte_array(key_bytes)?;
|
||||
let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
|
||||
Ok(env.byte_array_from_slice(&key.derive_room_id())?)
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
error::throw_error(&mut env, e);
|
||||
JByteArray::default()
|
||||
})
|
||||
unowned_env
|
||||
.with_env(|env| -> Result<_> {
|
||||
let key_bytes = env.convert_byte_array(key_bytes)?;
|
||||
let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
|
||||
Ok(env.byte_array_from_slice(&key.derive_room_id())?)
|
||||
})
|
||||
.resolve::<ThrowCallException>()
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn Java_org_signal_ringrtc_CallLinkRootKey_nativeToFormattedString<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
mut unowned_env: EnvUnowned<'local>,
|
||||
_class: JClass,
|
||||
key_bytes: JByteArray,
|
||||
) -> JString<'local> {
|
||||
try_scoped(|| {
|
||||
let key_bytes = env.convert_byte_array(key_bytes)?;
|
||||
let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
|
||||
Ok(env.new_string(key.to_formatted_string())?)
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
error::throw_error(&mut env, e);
|
||||
JString::default()
|
||||
})
|
||||
unowned_env
|
||||
.with_env(|env| -> Result<_> {
|
||||
let key_bytes = env.convert_byte_array(key_bytes)?;
|
||||
let key = CallLinkRootKey::try_from(key_bytes.as_slice())?;
|
||||
Ok(env.new_string(key.to_formatted_string())?)
|
||||
})
|
||||
.resolve::<ThrowCallException>()
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -8,9 +8,10 @@
|
||||
use std::{borrow::Cow, convert::TryFrom, panic, sync::Arc, time::Duration};
|
||||
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
objects::{GlobalRef, JByteArray, JClass, JObject, JString},
|
||||
sys::{jbyte, jint, jlong},
|
||||
Env, jni_sig, jni_str,
|
||||
objects::{JByteArray, JClass, JObject, JString},
|
||||
signature::FieldSignature,
|
||||
sys::{jbyte, jint, jlong, jobject},
|
||||
};
|
||||
use log::Level;
|
||||
|
||||
@ -18,7 +19,6 @@ use crate::{
|
||||
android::{
|
||||
android_platform::{AndroidCallContext, AndroidPlatform},
|
||||
error::AndroidError,
|
||||
jni_util::*,
|
||||
logging::init_logging,
|
||||
webrtc_peer_connection_factory::*,
|
||||
},
|
||||
@ -50,25 +50,23 @@ use crate::{
|
||||
pub type AndroidCallManager = CallManager<AndroidPlatform>;
|
||||
|
||||
/// CMI request for build time information
|
||||
pub fn get_build_info<'a>(env: &mut JNIEnv<'a>) -> Result<JObject<'a>> {
|
||||
pub fn get_build_info<'a>(env: &mut Env<'a>) -> Result<JObject<'a>> {
|
||||
#[cfg(all(debug_assertions, not(test)))]
|
||||
let debug = true;
|
||||
#[cfg(any(not(debug_assertions), test))]
|
||||
let debug = false;
|
||||
|
||||
let result = jni_new_object(
|
||||
Ok(jni_new_object!(
|
||||
env,
|
||||
jni_class_name!(org.signal.ringrtc.BuildInfo),
|
||||
jni_args!((debug => boolean) -> void),
|
||||
)?;
|
||||
|
||||
Ok(result)
|
||||
jni_str!("org/signal/ringrtc/BuildInfo"),
|
||||
(debug => boolean)
|
||||
)?)
|
||||
}
|
||||
|
||||
/// Library initialization routine.
|
||||
///
|
||||
/// Sets up the logging infrastructure.
|
||||
pub fn initialize(env: &mut JNIEnv) -> Result<()> {
|
||||
pub fn initialize(env: &mut Env) -> Result<()> {
|
||||
init_logging(env, Level::Debug)?;
|
||||
|
||||
// Set a custom panic handler that uses the logger instead of
|
||||
@ -81,7 +79,7 @@ pub fn initialize(env: &mut JNIEnv) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Creates a new AndroidCallManager object.
|
||||
pub fn create_call_manager(env: &mut JNIEnv, jni_call_manager: JObject) -> Result<jlong> {
|
||||
pub fn create_call_manager(env: &mut Env, jni_call_manager: JObject) -> Result<jlong> {
|
||||
let platform = AndroidPlatform::new(env, env.new_global_ref(jni_call_manager)?)?;
|
||||
|
||||
let http_client = http::DelegatingClient::new(platform.try_clone()?);
|
||||
@ -94,7 +92,7 @@ pub fn create_call_manager(env: &mut JNIEnv, jni_call_manager: JObject) -> Resul
|
||||
|
||||
/// Create a org.webrtc.PeerConnection object
|
||||
pub fn create_peer_connection(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
peer_connection_factory: jlong,
|
||||
mut native_connection: webrtc::ptr::Borrowed<Connection<AndroidPlatform>>,
|
||||
jni_rtc_config: JObject,
|
||||
@ -121,8 +119,8 @@ pub fn create_peer_connection(
|
||||
// construct JNI OwnedPeerConnection object
|
||||
let jni_owned_pc = unsafe {
|
||||
Java_org_webrtc_PeerConnectionFactory_nativeCreatePeerConnection(
|
||||
env.unsafe_clone(),
|
||||
JClass::from(JObject::null()),
|
||||
jni::EnvUnowned::from_raw(env.get_raw()),
|
||||
JClass::default(),
|
||||
peer_connection_factory,
|
||||
jni_rtc_config,
|
||||
jni_media_constraints,
|
||||
@ -161,7 +159,7 @@ pub fn create_peer_connection(
|
||||
|
||||
/// Application notification updating the current user's UUID
|
||||
pub fn set_self_uuid(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
uuid: JByteArray,
|
||||
) -> Result<()> {
|
||||
@ -171,7 +169,7 @@ pub fn set_self_uuid(
|
||||
|
||||
/// Adds an asset to the asset manager.
|
||||
pub fn add_asset(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
asset_group: JString,
|
||||
file_path: JString,
|
||||
@ -179,12 +177,12 @@ pub fn add_asset(
|
||||
) -> Result<()> {
|
||||
use crate::core::assets::AssetHandle;
|
||||
|
||||
let asset_group: String = env.get_string(&asset_group)?.into();
|
||||
let asset_group: String = asset_group.try_to_string(env)?;
|
||||
|
||||
let handle = if !content.is_null() {
|
||||
AssetHandle::Content(env.convert_byte_array(content)?)
|
||||
} else if !file_path.is_null() {
|
||||
let path: String = env.get_string(&file_path)?.into();
|
||||
let path: String = file_path.try_to_string(env)?;
|
||||
AssetHandle::FilePath(path)
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
@ -198,20 +196,20 @@ pub fn add_asset(
|
||||
|
||||
/// Application notification to start a new call
|
||||
pub fn call(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
jni_remote: JObject,
|
||||
call_media_type: CallMediaType,
|
||||
local_device_id: DeviceId,
|
||||
) -> Result<()> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let app_remote_peer = env.new_global_ref(jni_remote)?;
|
||||
let app_remote_peer = Arc::new(env.new_global_ref(jni_remote)?);
|
||||
call_manager.call(app_remote_peer, call_media_type, local_device_id)
|
||||
}
|
||||
|
||||
/// Application notification to proceed with a new call
|
||||
pub fn proceed(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
call_id: jlong,
|
||||
jni_call_context: JObject,
|
||||
@ -254,7 +252,7 @@ pub fn hangup(call_manager: *mut AndroidCallManager) -> Result<()> {
|
||||
|
||||
/// Application notification cancelling a group call ring
|
||||
pub fn cancel_group_ring(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
group_id: JByteArray,
|
||||
ring_id: jlong,
|
||||
@ -277,7 +275,7 @@ pub fn cancel_group_ring(
|
||||
/// Application notification of received answer message
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn received_answer(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
call_id: jlong,
|
||||
remote_peer: JObject,
|
||||
@ -288,7 +286,7 @@ pub fn received_answer(
|
||||
) -> Result<()> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let call_id = CallId::from(call_id);
|
||||
let remote_peer = env.new_global_ref(remote_peer)?;
|
||||
let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
|
||||
|
||||
let opaque = if opaque.is_null() {
|
||||
return Err(RingRtcError::OptionValueNotSet(
|
||||
@ -317,7 +315,7 @@ pub fn received_answer(
|
||||
/// Application notification of received offer message
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn received_offer(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
call_id: jlong,
|
||||
remote_peer: JObject,
|
||||
@ -331,7 +329,7 @@ pub fn received_offer(
|
||||
) -> Result<()> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let call_id = CallId::from(call_id);
|
||||
let remote_peer = env.new_global_ref(remote_peer)?;
|
||||
let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
|
||||
|
||||
let opaque = if opaque.is_null() {
|
||||
return Err(RingRtcError::OptionValueNotSet(
|
||||
@ -361,7 +359,7 @@ pub fn received_offer(
|
||||
|
||||
/// Application notification to add ICE candidates to a Connection
|
||||
pub fn received_ice(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
call_id: jlong,
|
||||
remote_peer: JObject,
|
||||
@ -370,14 +368,15 @@ pub fn received_ice(
|
||||
) -> Result<()> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let call_id = CallId::from(call_id);
|
||||
let remote_peer = env.new_global_ref(remote_peer)?;
|
||||
let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
|
||||
|
||||
// Convert Java list of byte[] into Rust Vector of IceCandidate
|
||||
let jni_ice_candidates = env.get_list(&candidates)?;
|
||||
let jni_ice_candidates = jni::objects::JList::cast_local(env, candidates)?;
|
||||
let mut ice_candidates = Vec::new();
|
||||
let mut iterator = jni_ice_candidates.iter(env)?;
|
||||
let iterator = jni_ice_candidates.iter(env)?;
|
||||
while let Some(jni_ice_candidate) = iterator.next(env)? {
|
||||
let jni_ice_candidate: JByteArray<'_> = jni_ice_candidate.into();
|
||||
// SAFETY: Java side must provide a `List<byte[]>`, so each element is `byte[]`.
|
||||
let jni_ice_candidate = unsafe { JByteArray::from_raw(env, jni_ice_candidate.as_raw()) };
|
||||
let opaque = env.convert_byte_array(jni_ice_candidate)?;
|
||||
ice_candidates.push(signaling::IceCandidate::new(opaque));
|
||||
}
|
||||
@ -396,7 +395,7 @@ pub fn received_ice(
|
||||
|
||||
/// Application notification of received Hangup message
|
||||
pub fn received_hangup(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
call_id: jlong,
|
||||
remote_peer: JObject,
|
||||
@ -406,7 +405,7 @@ pub fn received_hangup(
|
||||
) -> Result<()> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let call_id = CallId::from(call_id);
|
||||
let remote_peer = env.new_global_ref(remote_peer)?;
|
||||
let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
|
||||
|
||||
call_manager.received_hangup(
|
||||
remote_peer,
|
||||
@ -420,7 +419,7 @@ pub fn received_hangup(
|
||||
|
||||
/// Application notification of received Busy message
|
||||
pub fn received_busy(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
call_id: jlong,
|
||||
remote_peer: JObject,
|
||||
@ -428,7 +427,7 @@ pub fn received_busy(
|
||||
) -> Result<()> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let call_id = CallId::from(call_id);
|
||||
let remote_peer = env.new_global_ref(remote_peer)?;
|
||||
let remote_peer = Arc::new(env.new_global_ref(remote_peer)?);
|
||||
|
||||
call_manager.received_busy(
|
||||
remote_peer,
|
||||
@ -439,7 +438,7 @@ pub fn received_busy(
|
||||
|
||||
/// Application notification of received call message.
|
||||
pub fn received_call_message(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
sender_uuid: JByteArray,
|
||||
sender_device_id: DeviceId,
|
||||
@ -474,7 +473,7 @@ pub fn received_call_message(
|
||||
|
||||
/// Application notification of received HTTP response.
|
||||
pub fn received_http_response(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
request_id: jlong,
|
||||
status_code: jint,
|
||||
@ -512,22 +511,22 @@ pub fn accept_call(call_manager: *mut AndroidCallManager, call_id: jlong) -> Res
|
||||
call_manager.accept_call(call_id)
|
||||
}
|
||||
|
||||
/// CMI request for the active Connection object
|
||||
pub fn get_active_connection(call_manager: *mut AndroidCallManager) -> Result<GlobalRef> {
|
||||
/// CMI request to get the active Connection object (a raw jobject pointing to the Global ref)
|
||||
pub fn get_active_connection(call_manager: *mut AndroidCallManager) -> Result<jobject> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let connection = call_manager.active_connection()?;
|
||||
let android_connection = connection.app_connection()?;
|
||||
|
||||
Ok(android_connection.to_jni())
|
||||
Ok(android_connection.to_jni().as_raw())
|
||||
}
|
||||
|
||||
/// CMI request for the active CallContext object
|
||||
pub fn get_active_call_context(call_manager: *mut AndroidCallManager) -> Result<GlobalRef> {
|
||||
/// CMI request to get the active CallContext object (a raw jobject pointing to the Global ref)
|
||||
pub fn get_active_call_context(call_manager: *mut AndroidCallManager) -> Result<jobject> {
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
let call = call_manager.active_call()?;
|
||||
let android_call_context = call.call_context()?;
|
||||
|
||||
Ok(android_call_context.to_jni())
|
||||
Ok(android_call_context.to_jni().as_raw())
|
||||
}
|
||||
|
||||
/// CMI request to set the audio status
|
||||
@ -605,14 +604,14 @@ pub fn close(call_manager: *mut AndroidCallManager) -> Result<()> {
|
||||
// Call Links
|
||||
|
||||
pub fn read_call_link(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
sfu_url: JString,
|
||||
auth_credential_presentation: JByteArray,
|
||||
root_key: JByteArray,
|
||||
request_id: jlong,
|
||||
) -> Result<()> {
|
||||
let sfu_url = env.get_string(&sfu_url)?;
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
|
||||
let root_key =
|
||||
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
|
||||
@ -634,7 +633,7 @@ pub fn read_call_link(
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_call_link(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
sfu_url: JString,
|
||||
create_credential_presentation: JByteArray,
|
||||
@ -644,7 +643,7 @@ pub fn create_call_link(
|
||||
restrictions: jint,
|
||||
request_id: jlong,
|
||||
) -> Result<()> {
|
||||
let sfu_url = env.get_string(&sfu_url)?;
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
let create_credential_presentation = env.convert_byte_array(create_credential_presentation)?;
|
||||
let root_key =
|
||||
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
|
||||
@ -672,7 +671,7 @@ pub fn create_call_link(
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn update_call_link(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
sfu_url: JString,
|
||||
auth_credential_presentation: JByteArray,
|
||||
@ -683,7 +682,7 @@ pub fn update_call_link(
|
||||
new_revoked: jint,
|
||||
request_id: jlong,
|
||||
) -> Result<()> {
|
||||
let sfu_url = env.get_string(&sfu_url)?;
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
|
||||
let root_key =
|
||||
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
|
||||
@ -691,10 +690,10 @@ pub fn update_call_link(
|
||||
let new_name = if new_name.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(env.get_string(&new_name)?)
|
||||
Some(new_name.try_to_string(env)?)
|
||||
};
|
||||
let encrypted_name = new_name.map(|name| {
|
||||
let name = Cow::from(&name);
|
||||
let name: &str = &name;
|
||||
if name.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
@ -731,7 +730,7 @@ pub fn update_call_link(
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn delete_call_link(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
sfu_url: JString,
|
||||
auth_credential_presentation: JByteArray,
|
||||
@ -739,7 +738,7 @@ pub fn delete_call_link(
|
||||
admin_passkey: JByteArray,
|
||||
request_id: jlong,
|
||||
) -> Result<()> {
|
||||
let sfu_url = env.get_string(&sfu_url)?;
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
|
||||
let root_key =
|
||||
call_links::CallLinkRootKey::try_from(env.convert_byte_array(root_key)?.as_slice())?;
|
||||
@ -789,7 +788,7 @@ fn deserialize_to_group_member_info(
|
||||
}
|
||||
|
||||
pub fn peek_group_call(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
request_id: jlong,
|
||||
sfu_url: JString,
|
||||
@ -798,7 +797,7 @@ pub fn peek_group_call(
|
||||
) -> Result<()> {
|
||||
let request_id = request_id as u32;
|
||||
|
||||
let sfu_url = env.get_string(&sfu_url)?.into();
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
|
||||
let membership_proof = env.convert_byte_array(membership_proof)?;
|
||||
|
||||
@ -811,7 +810,7 @@ pub fn peek_group_call(
|
||||
}
|
||||
|
||||
pub fn peek_call_link_call(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
request_id: jlong,
|
||||
sfu_url: JString,
|
||||
@ -820,7 +819,7 @@ pub fn peek_call_link_call(
|
||||
) -> Result<()> {
|
||||
let request_id = request_id as u32;
|
||||
|
||||
let sfu_url = env.get_string(&sfu_url)?;
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
|
||||
let auth_credential_presentation = env.convert_byte_array(auth_credential_presentation)?;
|
||||
let root_key =
|
||||
@ -844,7 +843,7 @@ pub fn peek_call_link_call(
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_group_call_client(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
group_id: JByteArray,
|
||||
sfu_url: JString,
|
||||
@ -856,7 +855,7 @@ pub fn create_group_call_client(
|
||||
native_video_track_borrowed_rc: jlong,
|
||||
) -> Result<group_call::ClientId> {
|
||||
let group_id = env.convert_byte_array(group_id)?;
|
||||
let sfu_url = env.get_string(&sfu_url)?.into();
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
let hkdf_extra_info = env.convert_byte_array(hkdf_extra_info)?;
|
||||
|
||||
let peer_connection_factory = unsafe {
|
||||
@ -909,7 +908,7 @@ pub fn create_group_call_client(
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_call_link_call_client(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
sfu_url: JString,
|
||||
endorsement_public_key: JByteArray,
|
||||
@ -923,7 +922,7 @@ pub fn create_call_link_call_client(
|
||||
native_audio_track_borrowed_rc: jlong,
|
||||
native_video_track_borrowed_rc: jlong,
|
||||
) -> Result<group_call::ClientId> {
|
||||
let sfu_url = env.get_string(&sfu_url)?.into();
|
||||
let sfu_url = sfu_url.try_to_string(env)?;
|
||||
let endorsement_public_key = env.convert_byte_array(endorsement_public_key)?;
|
||||
let auth_presentation = env.convert_byte_array(auth_presentation)?;
|
||||
let root_key =
|
||||
@ -1086,7 +1085,7 @@ pub fn set_outgoing_group_call_video_is_screenshare(
|
||||
}
|
||||
|
||||
pub fn group_ring(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
recipient: JByteArray,
|
||||
@ -1122,51 +1121,53 @@ pub fn set_data_mode(
|
||||
}
|
||||
|
||||
pub fn request_video(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
jni_rendered_resolutions: JObject,
|
||||
active_speaker_height: jint,
|
||||
) -> Result<()> {
|
||||
// Convert Java list of VideoRequest into Rust Vec<group_call::VideoRequest>.
|
||||
let jni_rendered_resolution_list = env.get_list(&jni_rendered_resolutions)?;
|
||||
let jni_rendered_resolution_list =
|
||||
jni::objects::JList::cast_local(env, jni_rendered_resolutions)?;
|
||||
let mut rendered_resolutions: Vec<group_call::VideoRequest> = Vec::new();
|
||||
|
||||
let mut iterator = jni_rendered_resolution_list.iter(env)?;
|
||||
let iterator = jni_rendered_resolution_list.iter(env)?;
|
||||
while let Some(jni_rendered_resolution) = iterator.next(env)? {
|
||||
const LONG_TYPE: &str = jni_signature!(long);
|
||||
const INT_TYPE: &str = jni_signature!(int);
|
||||
const NULLABLE_INT_TYPE: &str = jni_signature!(java.lang.Integer);
|
||||
const LONG_TYPE: FieldSignature<'static> = jni_sig!(long);
|
||||
const INT_TYPE: FieldSignature<'static> = jni_sig!(int);
|
||||
const NULLABLE_INT_TYPE: FieldSignature<'static> = jni_sig!(java.lang.Integer);
|
||||
|
||||
const DEMUX_ID_FIELD: &str = "demuxId";
|
||||
let demux_id =
|
||||
jni_get_field(env, &jni_rendered_resolution, DEMUX_ID_FIELD, LONG_TYPE)?.j()?;
|
||||
let demux_id = env
|
||||
.get_field(&jni_rendered_resolution, jni_str!("demuxId"), &LONG_TYPE)?
|
||||
.into_long()?;
|
||||
let demux_id = demux_id as u32;
|
||||
|
||||
const WIDTH_FIELD: &str = "width";
|
||||
let width = jni_get_field(env, &jni_rendered_resolution, WIDTH_FIELD, INT_TYPE)?.i()?;
|
||||
let width = env
|
||||
.get_field(&jni_rendered_resolution, jni_str!("width"), &INT_TYPE)?
|
||||
.into_int()?;
|
||||
let width = width as u16;
|
||||
|
||||
const HEIGHT_FIELD: &str = "height";
|
||||
let height = jni_get_field(env, &jni_rendered_resolution, HEIGHT_FIELD, INT_TYPE)?.i()?;
|
||||
let height = env
|
||||
.get_field(&jni_rendered_resolution, jni_str!("height"), &INT_TYPE)?
|
||||
.into_int()?;
|
||||
let height = height as u16;
|
||||
|
||||
const FRAMERATE_FIELD: &str = "framerate";
|
||||
let framerate = jni_get_field(
|
||||
env,
|
||||
&jni_rendered_resolution,
|
||||
FRAMERATE_FIELD,
|
||||
NULLABLE_INT_TYPE,
|
||||
)?
|
||||
.l()?;
|
||||
let framerate = env
|
||||
.get_field(
|
||||
&jni_rendered_resolution,
|
||||
jni_str!("framerate"),
|
||||
&NULLABLE_INT_TYPE,
|
||||
)?
|
||||
.into_object()?;
|
||||
let framerate = if framerate.is_null() {
|
||||
None
|
||||
} else {
|
||||
// We have java.lang.Integer, so we need to invoke the function to get the actual
|
||||
// int value that is attached to it.
|
||||
match env.call_method(framerate, "intValue", jni_signature!(() -> int), &[]) {
|
||||
match env.call_method(framerate, jni_str!("intValue"), jni_sig!(() -> int), &[]) {
|
||||
Ok(jvalue) => {
|
||||
match jvalue.i() {
|
||||
match jvalue.into_int() {
|
||||
Ok(int) => Some(int.to_owned() as u16),
|
||||
Err(_) => {
|
||||
// The framerate can be ignored.
|
||||
@ -1201,7 +1202,7 @@ pub fn request_video(
|
||||
}
|
||||
|
||||
pub fn approve_user(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
other_user_id: JByteArray,
|
||||
@ -1213,7 +1214,7 @@ pub fn approve_user(
|
||||
}
|
||||
|
||||
pub fn deny_user(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
other_user_id: JByteArray,
|
||||
@ -1245,7 +1246,7 @@ pub fn block_client(
|
||||
}
|
||||
|
||||
pub fn set_group_members(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
jni_serialized_group_members: JByteArray,
|
||||
@ -1258,7 +1259,7 @@ pub fn set_group_members(
|
||||
}
|
||||
|
||||
pub fn set_membership_proof(
|
||||
env: &JNIEnv,
|
||||
env: &Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
proof: JByteArray,
|
||||
@ -1270,12 +1271,12 @@ pub fn set_membership_proof(
|
||||
}
|
||||
|
||||
pub fn react(
|
||||
env: &mut JNIEnv,
|
||||
env: &mut Env,
|
||||
call_manager: *mut AndroidCallManager,
|
||||
client_id: group_call::ClientId,
|
||||
value: JString,
|
||||
) -> Result<()> {
|
||||
let value = env.get_string(&value)?.into();
|
||||
let value: String = value.try_to_string(env)?;
|
||||
let call_manager = unsafe { ptr_as_mut(call_manager)? };
|
||||
call_manager.react(client_id, value);
|
||||
Ok(())
|
||||
|
||||
@ -5,40 +5,76 @@
|
||||
|
||||
//! Android Error Codes and Utilities.
|
||||
|
||||
use anyhow::Error;
|
||||
use jni::{JNIEnv, errors, objects::JThrowable};
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
|
||||
use jni::{
|
||||
Env,
|
||||
errors::ErrorPolicy,
|
||||
jni_str,
|
||||
objects::JThrowable,
|
||||
strings::{JNIStr, JNIString},
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{android::jni_util::*, core::util::try_scoped};
|
||||
use crate::core::util::try_scoped;
|
||||
|
||||
const CALL_EXCEPTION_CLASS: &str = jni_class_name!(org.signal.ringrtc.CallException);
|
||||
const CALL_EXCEPTION_CLASS: &JNIStr = jni_str!("org/signal/ringrtc/CallException");
|
||||
|
||||
/// Convert a `Error` into a Java `org.signal.ringrtc.CallException`
|
||||
/// and throw it.
|
||||
///
|
||||
/// This is used to communicate synchronous errors to the client
|
||||
/// application.
|
||||
pub fn throw_error(env: &mut JNIEnv, error: Error) {
|
||||
if let Ok(exception) = env.exception_occurred() {
|
||||
if env.exception_clear().is_ok() {
|
||||
/// `ErrorPolicy` that converts Rust errors and panics into a Java
|
||||
/// `org.signal.ringrtc.CallException` and throws it to the client.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ThrowCallException;
|
||||
|
||||
impl<T: Default> ErrorPolicy<T, anyhow::Error> for ThrowCallException {
|
||||
type Captures<'unowned_env_local: 'native_method, 'native_method> = ();
|
||||
|
||||
fn on_error<'unowned_env_local: 'native_method, 'native_method>(
|
||||
env: &mut Env<'unowned_env_local>,
|
||||
_cap: &mut Self::Captures<'unowned_env_local, 'native_method>,
|
||||
err: anyhow::Error,
|
||||
) -> jni::errors::Result<T> {
|
||||
// If the closure returned an error while a Java exception was already
|
||||
// pending, preserve that exception as the cause.
|
||||
if let Some(exception) = env.exception_occurred() {
|
||||
env.exception_clear();
|
||||
let _ = try_scoped(|| {
|
||||
let message = env.new_string(error.to_string())?;
|
||||
let call_exception: JThrowable = jni_new_object(
|
||||
env,
|
||||
CALL_EXCEPTION_CLASS,
|
||||
jni_args!((
|
||||
message => java.lang.String,
|
||||
exception => java.lang.Throwable,
|
||||
) -> void),
|
||||
)?
|
||||
.into();
|
||||
Ok(env.throw(call_exception)?)
|
||||
let message = env.new_string(err.to_string())?;
|
||||
let call_exception = jni_new_object!(env, CALL_EXCEPTION_CLASS, (
|
||||
message => java.lang.String,
|
||||
exception => java.lang.Throwable,
|
||||
))?;
|
||||
// SAFETY: We just constructed CallException, which extends Throwable.
|
||||
let throwable = unsafe { JThrowable::from_raw(env, call_exception.as_raw()) };
|
||||
Ok(env.throw(throwable)?)
|
||||
});
|
||||
} else {
|
||||
// Don't try to throw our own exception on top of another exception.
|
||||
let jni_msg = JNIString::from(format!("{}", err));
|
||||
let _ = env.throw_new(CALL_EXCEPTION_CLASS, &jni_msg);
|
||||
}
|
||||
} else {
|
||||
let _ = env.throw_new(CALL_EXCEPTION_CLASS, format!("{}", error));
|
||||
Ok(T::default())
|
||||
}
|
||||
|
||||
fn on_panic<'unowned_env_local: 'native_method, 'native_method>(
|
||||
env: &mut Env<'unowned_env_local>,
|
||||
_cap: &mut Self::Captures<'unowned_env_local, 'native_method>,
|
||||
payload: Box<dyn std::any::Any + Send + 'static>,
|
||||
) -> jni::errors::Result<T> {
|
||||
let panic_string = match payload.downcast::<&'static str>() {
|
||||
Ok(s) => (*s).to_string(),
|
||||
Err(payload) => match payload.downcast::<String>() {
|
||||
Ok(s) => *s,
|
||||
Err(payload) => {
|
||||
if let Err(drop_panic) = catch_unwind(AssertUnwindSafe(|| drop(payload))) {
|
||||
log::error!("Panic while dropping panic payload: {:?}", drop_panic);
|
||||
std::mem::forget(drop_panic);
|
||||
}
|
||||
"".to_string()
|
||||
}
|
||||
},
|
||||
};
|
||||
let jni_msg = JNIString::from(format!("Rust panic: {panic_string}"));
|
||||
let _ = env.throw_new(CALL_EXCEPTION_CLASS, &jni_msg);
|
||||
Ok(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,29 +84,9 @@ pub enum AndroidError {
|
||||
// Android JNI error codes
|
||||
#[error("JNI: static method lookup failed. Class: {0}, Method: {1}, Sig: {2}")]
|
||||
JniStaticMethodLookup(String, String, String),
|
||||
#[error("JNI: calling method failed. Method: {0}, Sig: {1}, Error: {2}")]
|
||||
JniCallMethod(String, String, errors::Error),
|
||||
#[error("JNI: calling static method failed. Class: {0}, Method: {1}, Sig: {2}")]
|
||||
JniCallStaticMethod(String, String, String),
|
||||
#[error("JNI: calling constructor failed. Constructor: {0}, Sig: {1}")]
|
||||
JniCallConstructor(String, String),
|
||||
#[error("JNI: getting field failed. Field: {0}, Type: {1}")]
|
||||
JniGetField(String, String),
|
||||
#[error("JNI: class not found. Type: {0} Add to the cache?")]
|
||||
JniGetLangClassNotFound(String),
|
||||
#[error("JNI: new object failed. Type: {0}")]
|
||||
JniNewLangObjectFailed(String),
|
||||
#[error("JNI: invalid serialized buffer.")]
|
||||
JniInvalidSerializedBuffer,
|
||||
|
||||
// Android Class Cache error codes
|
||||
#[error("ClassCache: Class is already in cache: {0}")]
|
||||
ClassCacheDuplicate(String),
|
||||
#[error("ClassCache: class not found in jvm: {0}")]
|
||||
ClassCacheNotFound(String),
|
||||
#[error("ClassCache: class not found in cache: {0}")]
|
||||
ClassCacheLookup(String),
|
||||
|
||||
// Android Misc error codes
|
||||
#[error("Creating JNI PeerConnection failed")]
|
||||
CreateJniPeerConnection,
|
||||
|
||||
@ -1,31 +1,11 @@
|
||||
//
|
||||
// Copyright 2019-2021 Signal Messenger, LLC
|
||||
// Copyright 2019-2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
//! Utility helpers for JNI access
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::{TryFrom, TryInto},
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
objects::{GlobalRef, JClass, JObject, JValue, JValueOwned},
|
||||
};
|
||||
|
||||
use crate::{android::error::AndroidError, common::Result, core::util::try_scoped};
|
||||
pub use crate::{jni_class_name, jni_signature};
|
||||
|
||||
macro_rules! jni_arg {
|
||||
( $arg:expr => boolean ) => {
|
||||
<jni::objects::JValue as From<bool>>::from($arg)
|
||||
};
|
||||
// jni_signature will reject this, but having it do something reasonable avoids multiple errors.
|
||||
( $arg:expr => bool ) => {
|
||||
<jni::objects::JValue as From<bool>>::from($arg)
|
||||
jni::objects::JValue::Bool($arg)
|
||||
};
|
||||
( $arg:expr => byte ) => {
|
||||
jni::objects::JValue::Byte($arg)
|
||||
@ -54,306 +34,58 @@ macro_rules! jni_arg {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! jni_return_type {
|
||||
// Unfortunately there's not a conversion directly from JValue to bool, only jboolean.
|
||||
(boolean) => {
|
||||
jni::sys::jboolean
|
||||
};
|
||||
// jni_signature will reject this, but having it do something reasonable avoids multiple errors.
|
||||
(bool) => {
|
||||
jni::sys::jboolean
|
||||
};
|
||||
(byte) => {
|
||||
jni::sys::jbyte
|
||||
};
|
||||
(char) => {
|
||||
jni::sys::jchar
|
||||
};
|
||||
(short) => {
|
||||
jni::sys::jshort
|
||||
};
|
||||
(int) => {
|
||||
jni::sys::jint
|
||||
};
|
||||
(long) => {
|
||||
jni::sys::jlong
|
||||
};
|
||||
(float) => {
|
||||
jni::sys::jfloat
|
||||
};
|
||||
(double) => {
|
||||
jni::sys::jdouble
|
||||
};
|
||||
(void) => {
|
||||
()
|
||||
};
|
||||
// Assume anything else is an object. This includes arrays and classes.
|
||||
($($_:tt)+) => {
|
||||
jni::objects::JObject
|
||||
};
|
||||
}
|
||||
|
||||
/// Represents a return type, used by [`JniArgs`].
|
||||
///
|
||||
/// This is an implementation detail of [`jni_args`] and [`JniArgs`]. Using a function type makes
|
||||
/// `JniArgs` covariant, which allows the compiler to be less strict about the lifetime marker.
|
||||
pub type PhantomReturnType<R> = PhantomData<fn() -> R>;
|
||||
|
||||
/// A JNI argument list, type-checked with its signature.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct JniArgs<'local, 'obj_ref, R, const LEN: usize> {
|
||||
pub sig: &'static str,
|
||||
pub args: [JValue<'local, 'obj_ref>; LEN],
|
||||
pub _return: PhantomReturnType<R>,
|
||||
}
|
||||
|
||||
/// Produces a JniArgs struct from the given arguments and return type.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// let args = jni_args!((name => java.lang.String, 0x3FFF => short) -> void);
|
||||
/// assert_eq!(args.sig, "(Ljava/lang/String;S)V");
|
||||
/// assert_eq!(args.args.len(), 2);
|
||||
/// ```
|
||||
/// Builds a `(MethodSignature, [JValue; N])` tuple from a Java-style arg list.
|
||||
macro_rules! jni_args {
|
||||
(
|
||||
(
|
||||
$( $arg:expr => $arg_base:tt $(. $arg_rest:ident)* $(:: $arg_nested:ident)* ),* $(,)?
|
||||
) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
|
||||
) => {
|
||||
JniArgs {
|
||||
sig: jni_signature!(
|
||||
(
|
||||
jni::jni_sig!(
|
||||
(
|
||||
$( $arg_base $(. $arg_rest)* $(:: $arg_nested)* ),*
|
||||
) -> $ret_base $(. $ret_rest)* $(:: $ret_nested)*
|
||||
),
|
||||
args: [$(jni_arg!($arg => $arg_base)),*],
|
||||
_return: PhantomReturnType::<jni_return_type!($ret_base)> {},
|
||||
}
|
||||
[$(jni_arg!($arg => $arg_base)),*],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around JNIEnv::call_method() with logging.
|
||||
pub fn jni_call_method<
|
||||
'input,
|
||||
'output,
|
||||
O: AsRef<JObject<'input>>,
|
||||
R: TryFrom<JValueOwned<'output>, Error = jni::errors::Error>,
|
||||
const LEN: usize,
|
||||
>(
|
||||
env: &mut JNIEnv<'output>,
|
||||
object: O,
|
||||
name: &'static str,
|
||||
args: JniArgs<R, LEN>,
|
||||
) -> Result<R> {
|
||||
env.call_method(object, name, args.sig, &args.args)
|
||||
.and_then(|v| v.try_into())
|
||||
.map_err(|e| AndroidError::JniCallMethod(name.to_string(), args.sig.to_string(), e).into())
|
||||
}
|
||||
|
||||
/// Wrapper around JNIEnv::call_static_method() with logging.
|
||||
#[allow(dead_code)]
|
||||
pub fn jni_call_static_method<
|
||||
'output,
|
||||
R: TryFrom<JValueOwned<'output>, Error = jni::errors::Error>,
|
||||
const LEN: usize,
|
||||
>(
|
||||
env: &mut JNIEnv<'output>,
|
||||
class: &'static str,
|
||||
name: &'static str,
|
||||
args: JniArgs<R, LEN>,
|
||||
) -> Result<R> {
|
||||
env.call_static_method(class, name, args.sig, &args.args)
|
||||
.and_then(|v| v.try_into())
|
||||
.map_err(|e| AndroidError::JniCallMethod(name.to_string(), args.sig.to_string(), e).into())
|
||||
}
|
||||
|
||||
/// Wrapper around JNIEnv::new_object() with logging.
|
||||
pub fn jni_new_object<'output, const LEN: usize>(
|
||||
env: &mut JNIEnv<'output>,
|
||||
class: &'static str,
|
||||
args: JniArgs<(), LEN>,
|
||||
) -> Result<JObject<'output>> {
|
||||
match env.new_object(class, args.sig, &args.args) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(_) => {
|
||||
Err(AndroidError::JniCallConstructor(class.to_string(), args.sig.to_string()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around JNIEnv::get_field() with logging.
|
||||
pub fn jni_get_field<'input, 'output, O: AsRef<JObject<'input>>>(
|
||||
env: &mut JNIEnv<'output>,
|
||||
object: O,
|
||||
name: &'static str,
|
||||
ty: &'static str,
|
||||
) -> Result<JValueOwned<'output>> {
|
||||
env.get_field(object, name, ty)
|
||||
.map_err(|_| AndroidError::JniGetField(name.to_string(), ty.to_string()).into())
|
||||
}
|
||||
|
||||
/// Creates a new java.util.ArrayList object
|
||||
pub fn jni_new_arraylist<'output>(
|
||||
env: &mut JNIEnv<'output>,
|
||||
initial_capacity: usize,
|
||||
) -> Result<JObject<'output>> {
|
||||
jni_new_object(
|
||||
env,
|
||||
jni_class_name!(java.util.ArrayList),
|
||||
jni_args!((initial_capacity.try_into().expect("too big for Java") => int) -> void),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new java.util.HashMap object
|
||||
pub fn jni_new_hashmap<'output>(
|
||||
env: &mut JNIEnv<'output>,
|
||||
initial_capacity: usize,
|
||||
) -> Result<JObject<'output>> {
|
||||
jni_new_object(
|
||||
env,
|
||||
jni_class_name!(java.util.HashMap),
|
||||
jni_args!((initial_capacity.try_into().expect("too big for Java") => int) -> void),
|
||||
)
|
||||
}
|
||||
|
||||
/// Prints local and global references to the log.
|
||||
#[allow(dead_code)]
|
||||
pub fn dump_references(env: &mut JNIEnv) {
|
||||
let _ = env.with_local_frame(5, |env| -> Result<()> {
|
||||
info!("Dumping references ->");
|
||||
let _ = env.call_static_method(
|
||||
jni_class_name!(dalvik.system.VMDebug),
|
||||
"dumpReferenceTables",
|
||||
jni_signature!(() -> void),
|
||||
&[],
|
||||
/// Calls `Env::call_method` with the given args. Returns `Result<JValueOwned>`.
|
||||
///
|
||||
/// Use trailing `.into_<type>` to unwrap a typed return.
|
||||
macro_rules! jni_call_method {
|
||||
(
|
||||
$env:expr, $obj:expr, $name:expr,
|
||||
( $($arg_list:tt)* ) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
|
||||
) => {{
|
||||
let (sig, args) = jni_args!(
|
||||
( $($arg_list)* ) -> $ret_base $(. $ret_rest)* $(:: $ret_nested)*
|
||||
);
|
||||
info!("<- Done with references");
|
||||
|
||||
Ok(())
|
||||
});
|
||||
$env.call_method($obj, $name, &sig, &args)
|
||||
}};
|
||||
}
|
||||
|
||||
/// A cache of Java class objects
|
||||
/// Calls `Env::call_static_method` with the given args. Returns `Result<JValueOwned>`.
|
||||
macro_rules! jni_call_static_method {
|
||||
(
|
||||
$env:expr, $class:expr, $name:expr,
|
||||
( $($arg_list:tt)* ) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
|
||||
) => {{
|
||||
let (sig, args) = jni_args!(
|
||||
( $($arg_list)* ) -> $ret_base $(. $ret_rest)* $(:: $ret_nested)*
|
||||
);
|
||||
$env.call_static_method($class, $name, &sig, &args)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Calls `Env::new_object` with the given args. Returns `Result<JObject>`.
|
||||
///
|
||||
/// JNI cannot lookup classes by name from threads other than the main
|
||||
/// thread. See this FAQ for background:
|
||||
/// https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class
|
||||
///
|
||||
/// The solution here is to look up the class objects at init time on
|
||||
/// the main thread and cache a global reference to the object for
|
||||
/// later use.
|
||||
#[derive(Clone)]
|
||||
pub struct ClassCache {
|
||||
/// HashMap mapping the class name (String) to Java object
|
||||
map: HashMap<String, GlobalRef>,
|
||||
}
|
||||
|
||||
impl ClassCache {
|
||||
/// Returns an empty cache
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Look up the class specified by `class_name` and store a global
|
||||
/// reference to the class object result in the cache.
|
||||
///
|
||||
/// * Adding the same class twice is treated as an error.
|
||||
/// * If the class lookup fails, return an error.
|
||||
pub fn add_class(&mut self, env: &mut JNIEnv, class_name: &str) -> Result<()> {
|
||||
if self.map.contains_key(class_name) {
|
||||
return Err(AndroidError::ClassCacheDuplicate(class_name.to_string()).into());
|
||||
}
|
||||
|
||||
let class_object = match env.find_class(class_name) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return Err(AndroidError::ClassCacheNotFound(class_name.to_string()).into()),
|
||||
};
|
||||
|
||||
let class_ref = env.new_global_ref(JObject::from(class_object))?;
|
||||
self.map.insert(String::from(class_name), class_ref);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve the class object specified by `class_name` and return it.
|
||||
///
|
||||
/// * If the class is not in the cache, return an error.
|
||||
pub fn get_class(&self, class_name: &str) -> Result<&JClass<'_>> {
|
||||
if let Some(class_ref) = self.map.get(class_name) {
|
||||
let object = class_ref.as_obj();
|
||||
Ok(<&JClass>::from(object))
|
||||
} else {
|
||||
Err(AndroidError::ClassCacheLookup(class_name.to_string()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around [`JNIEnv`] that reports uncaught exceptions on destruction.
|
||||
///
|
||||
/// Normally JNI handles uncaught exceptions when a native thread is "detached" from the JVM, but
|
||||
/// RingRTC treats all its callback threads as "daemon" threads that are only detached when the
|
||||
/// native thread exits. This regains that functionality.
|
||||
///
|
||||
/// Because `ExceptionCheckingJNIEnv` implements `Deref`, it should be a drop-in replacement for
|
||||
/// most uses of JNIEnv as a value. References to JNIEnv should continue as references.
|
||||
pub struct ExceptionCheckingJNIEnv<'a>(JNIEnv<'a>);
|
||||
|
||||
impl Drop for ExceptionCheckingJNIEnv<'_> {
|
||||
fn drop(&mut self) {
|
||||
let result = try_scoped(|| {
|
||||
let exception = self.exception_occurred()?;
|
||||
if exception.is_null() {
|
||||
return Ok(());
|
||||
}
|
||||
self.exception_clear()?;
|
||||
let thread = jni_call_static_method(
|
||||
self,
|
||||
jni_class_name!(java.lang.Thread),
|
||||
"currentThread",
|
||||
jni_args!(() -> java.lang.Thread),
|
||||
)?;
|
||||
let handler = jni_call_method(
|
||||
self,
|
||||
&thread,
|
||||
"getUncaughtExceptionHandler",
|
||||
jni_args!(() -> java.lang.Thread::UncaughtExceptionHandler),
|
||||
)?;
|
||||
jni_call_method(
|
||||
self,
|
||||
handler,
|
||||
"uncaughtException",
|
||||
jni_args!((thread => java.lang.Thread, exception => java.lang.Throwable) -> void),
|
||||
)?;
|
||||
Ok(())
|
||||
});
|
||||
match result {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
error!("unable to rethrow exception: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<JNIEnv<'a>> for ExceptionCheckingJNIEnv<'a> {
|
||||
fn from(env: JNIEnv<'a>) -> Self {
|
||||
Self(env)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Deref for ExceptionCheckingJNIEnv<'a> {
|
||||
type Target = JNIEnv<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for ExceptionCheckingJNIEnv<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
/// The constructor's JNI return type is always `void`; this macro embeds that.
|
||||
macro_rules! jni_new_object {
|
||||
( $env:expr, $class:expr, ( $($arg_list:tt)* ) $(,)? ) => {{
|
||||
let (sig, args) = jni_args!(( $($arg_list)* ) -> void);
|
||||
$env.new_object($class, &sig, &args)
|
||||
}};
|
||||
}
|
||||
|
||||
@ -6,39 +6,27 @@
|
||||
//! Setup Android logging object
|
||||
|
||||
use jni::{
|
||||
JNIEnv, JavaVM,
|
||||
objects::{GlobalRef, JObject},
|
||||
Env, JavaVM, jni_sig, jni_str,
|
||||
objects::{Global, JObject},
|
||||
signature::MethodSignature,
|
||||
strings::JNIStr,
|
||||
};
|
||||
use log::{Level, Log, Metadata, Record};
|
||||
|
||||
use crate::{
|
||||
android::{error::AndroidError, jni_util::*},
|
||||
common::Result,
|
||||
};
|
||||
use crate::{android::error::AndroidError, common::Result};
|
||||
|
||||
/// Log object for interfacing with existing Android logger.
|
||||
struct AndroidLogger {
|
||||
level: Level,
|
||||
jvm: JavaVM,
|
||||
logger_class: GlobalRef,
|
||||
logger_class: Global<jni::objects::JClass<'static>>,
|
||||
}
|
||||
|
||||
// Method name and signature required of Java logger class
|
||||
// void log(int level, String message)
|
||||
const LOGGER_CLASS: &str = jni_class_name!(org.signal.ringrtc.Log);
|
||||
const LOGGER_METHOD: &str = "log";
|
||||
const LOGGER_SIG: &str = jni_signature!((int, java.lang.String) -> void);
|
||||
|
||||
impl AndroidLogger {
|
||||
// This is specifically *not* using ExceptionCheckingJNIEnv:
|
||||
// - We may be logging in the middle of some other operation, which might be able to handle
|
||||
// uncaught exceptions.
|
||||
// - ExceptionCheckingJNIEnv itself can log in failure cases, and we don't want an infinite
|
||||
// loop.
|
||||
fn get_java_env(&self) -> Result<JNIEnv<'_>> {
|
||||
Ok(self.jvm.attach_current_thread_as_daemon()?)
|
||||
}
|
||||
}
|
||||
const LOGGER_CLASS: &JNIStr = jni_str!("org/signal/ringrtc/Log");
|
||||
const LOGGER_METHOD: &JNIStr = jni_str!("log");
|
||||
const LOGGER_SIG: MethodSignature<'static, 'static> = jni_sig!((int, java.lang.String) -> void);
|
||||
|
||||
impl Log for AndroidLogger {
|
||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
@ -54,25 +42,6 @@ impl Log for AndroidLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the `JavaVM` interface to attach a `JNIEnv` to the current thread.
|
||||
let mut env = match self.get_java_env() {
|
||||
Ok(v) => v,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Attempt to clear any exception before we log anything.
|
||||
// We'll rethrow it after logging.
|
||||
let exception = env
|
||||
.exception_occurred()
|
||||
.unwrap_or_else(|_| JObject::null().into());
|
||||
if !exception.is_null() {
|
||||
let exception_cleared = env.exception_clear();
|
||||
if exception_cleared.is_err() {
|
||||
// If we can't clear the exception, skip the log.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let get_file_name = || -> Option<&str> {
|
||||
let file = record.file()?;
|
||||
file.split(std::path::MAIN_SEPARATOR_STR).last()
|
||||
@ -89,43 +58,61 @@ impl Log for AndroidLogger {
|
||||
|
||||
let level = record.level() as i32;
|
||||
|
||||
let _ = env.with_local_frame(5, |env| -> Result<()> {
|
||||
let msg = match env.new_string(message) {
|
||||
Ok(v) => JObject::from(v),
|
||||
Err(_) => return Ok(()),
|
||||
};
|
||||
let _ = self.jvm.attach_current_thread(|env| -> Result<()> {
|
||||
// Attempt to clear any exception before we log anything.
|
||||
// We'll rethrow it after logging.
|
||||
let exception = env.exception_occurred();
|
||||
let had_exception = exception.is_some();
|
||||
if had_exception {
|
||||
env.exception_clear();
|
||||
}
|
||||
|
||||
let values = [level.into(), (&msg).into()];
|
||||
let _ = env.with_local_frame(5, |env| -> Result<()> {
|
||||
let msg = match env.new_string(&message) {
|
||||
Ok(v) => JObject::from(v),
|
||||
Err(_) => return Ok(()),
|
||||
};
|
||||
|
||||
let values = [level.into(), (&msg).into()];
|
||||
|
||||
// Ignore the result here, can't do anything about it anyway.
|
||||
let _ = env.call_static_method(
|
||||
&self.logger_class,
|
||||
LOGGER_METHOD,
|
||||
&LOGGER_SIG,
|
||||
&values,
|
||||
);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// If we put an exception "on hold" earlier, try to throw it again now.
|
||||
if let Some(exception) = exception
|
||||
&& had_exception
|
||||
{
|
||||
// But check that there hasn't been *another* exception thrown.
|
||||
if env.exception_occurred().is_none() {
|
||||
let _ = env.throw(exception);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore the result here, can't do anything about it anyway.
|
||||
let _ =
|
||||
env.call_static_method(&self.logger_class, LOGGER_METHOD, LOGGER_SIG, &values);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// If we put an exception "on hold" earlier, try to throw it again now.
|
||||
if !exception.is_null() {
|
||||
// But check that there hasn't been *another* exception thrown.
|
||||
if let Ok(false) = env.exception_check() {
|
||||
let _ = env.throw(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
pub fn init_logging(env: &mut JNIEnv, level: Level) -> Result<()> {
|
||||
pub fn init_logging(env: &mut Env, level: Level) -> Result<()> {
|
||||
// Check if the Logger class contains a good logger method and signature
|
||||
if env
|
||||
.get_static_method_id(LOGGER_CLASS, LOGGER_METHOD, LOGGER_SIG)
|
||||
.get_static_method_id(LOGGER_CLASS, LOGGER_METHOD, &LOGGER_SIG)
|
||||
.is_err()
|
||||
{
|
||||
return Err(AndroidError::JniStaticMethodLookup(
|
||||
String::from(LOGGER_CLASS),
|
||||
String::from(LOGGER_METHOD),
|
||||
String::from(LOGGER_SIG),
|
||||
LOGGER_CLASS.to_string(),
|
||||
LOGGER_METHOD.to_string(),
|
||||
LOGGER_SIG.sig().to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
@ -134,11 +121,11 @@ pub fn init_logging(env: &mut JNIEnv, level: Level) -> Result<()> {
|
||||
// main thread, so stash a global ref to the class now, while
|
||||
// we're on the main thread.
|
||||
let logger_class = env.find_class(LOGGER_CLASS)?;
|
||||
let logger_class = env.new_global_ref(JObject::from(logger_class))?;
|
||||
let logger_class = env.new_global_ref(logger_class)?;
|
||||
|
||||
// `JNIEnv` cannot be sent across thread boundaries. To be able to use JNI
|
||||
// `Env` cannot be sent across thread boundaries. To be able to use JNI
|
||||
// functions in other threads, we must first obtain the `JavaVM` interface
|
||||
// which, unlike `JNIEnv` is `Send`.
|
||||
// which, unlike `Env` is `Send`.
|
||||
let jvm = env.get_java_vm()?;
|
||||
let logger = AndroidLogger {
|
||||
level,
|
||||
|
||||
114
src/rust/src/android/types.rs
Normal file
114
src/rust/src/android/types.rs
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// Copyright 2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
use jni::{
|
||||
Env, bind_java_type,
|
||||
refs::{LoaderContext, Reference as _},
|
||||
};
|
||||
|
||||
// RingRTC App Classes
|
||||
bind_java_type! { pub CallSummary => org.signal.ringrtc.CallSummary }
|
||||
bind_java_type! { pub QualityStats => org.signal.ringrtc.CallSummary::QualityStats }
|
||||
bind_java_type! { pub MediaQualityStats => org.signal.ringrtc.CallSummary::MediaQualityStats }
|
||||
bind_java_type! { pub CallLinkState => org.signal.ringrtc.CallLinkState }
|
||||
bind_java_type! { pub CallLinkRootKey => org.signal.ringrtc.CallLinkRootKey }
|
||||
bind_java_type! { pub HttpHeader => org.signal.ringrtc.HttpHeader }
|
||||
bind_java_type! { pub HttpResult => org.signal.ringrtc.CallManager::HttpResult }
|
||||
bind_java_type! { pub PeekInfo => org.signal.ringrtc.PeekInfo }
|
||||
bind_java_type! { pub Reaction => org.signal.ringrtc.GroupCall::Reaction }
|
||||
bind_java_type! { pub RemoteDeviceState => org.signal.ringrtc.GroupCall::RemoteDeviceState }
|
||||
bind_java_type! { pub ReceivedAudioLevel => org.signal.ringrtc.GroupCall::ReceivedAudioLevel }
|
||||
|
||||
// RingRTC Enum Classes
|
||||
bind_java_type! {
|
||||
pub CallEvent => org.signal.ringrtc.CallManager::CallEvent,
|
||||
methods { static fn from_native_index(value: jint) -> CallEvent }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub CallMediaType => org.signal.ringrtc.CallManager::CallMediaType,
|
||||
methods { static fn from_native_index(value: jint) -> CallMediaType }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub HangupType => org.signal.ringrtc.CallManager::HangupType,
|
||||
methods { static fn from_native_index(value: jint) -> HangupType }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub HttpMethod => org.signal.ringrtc.CallManager::HttpMethod,
|
||||
methods { static fn from_native_index(value: jint) -> HttpMethod }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub CallEndReason => org.signal.ringrtc.CallManager::CallEndReason,
|
||||
methods { static fn from_native_index(value: jint) -> CallEndReason }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub ConnectionState => org.signal.ringrtc.GroupCall::ConnectionState,
|
||||
methods { static fn from_native_index(value: jint) -> ConnectionState }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub JoinState => org.signal.ringrtc.GroupCall::JoinState,
|
||||
methods { static fn from_native_index(value: jint) -> JoinState }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub SpeechEvent => org.signal.ringrtc.GroupCall::SpeechEvent,
|
||||
methods { static fn from_native_index(value: jint) -> SpeechEvent }
|
||||
}
|
||||
|
||||
// JDK Primitives
|
||||
bind_java_type! {
|
||||
pub JBoolean => java.lang.Boolean,
|
||||
constructors { fn new(value: jboolean) }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub JFloat => java.lang.Float,
|
||||
constructors { fn new(value: jfloat) }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub JInteger => java.lang.Integer,
|
||||
constructors { fn new(value: jint) }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub JLong => java.lang.Long,
|
||||
constructors { fn new(value: jlong) }
|
||||
}
|
||||
|
||||
// JDK Collections
|
||||
bind_java_type! {
|
||||
pub JArrayList => java.util.ArrayList,
|
||||
constructors { fn with_capacity(initial_capacity: jint) }
|
||||
}
|
||||
bind_java_type! {
|
||||
pub JHashMap => java.util.HashMap,
|
||||
constructors { fn with_capacity(initial_capacity: jint) }
|
||||
}
|
||||
|
||||
pub fn init_class_cache(env: &mut Env) -> jni::errors::Result<()> {
|
||||
let ctx = LoaderContext::default();
|
||||
CallSummary::lookup_class(env, &ctx)?;
|
||||
QualityStats::lookup_class(env, &ctx)?;
|
||||
MediaQualityStats::lookup_class(env, &ctx)?;
|
||||
CallLinkState::lookup_class(env, &ctx)?;
|
||||
CallLinkRootKey::lookup_class(env, &ctx)?;
|
||||
HttpHeader::lookup_class(env, &ctx)?;
|
||||
HttpResult::lookup_class(env, &ctx)?;
|
||||
PeekInfo::lookup_class(env, &ctx)?;
|
||||
Reaction::lookup_class(env, &ctx)?;
|
||||
RemoteDeviceState::lookup_class(env, &ctx)?;
|
||||
ReceivedAudioLevel::lookup_class(env, &ctx)?;
|
||||
CallEvent::lookup_class(env, &ctx)?;
|
||||
CallMediaType::lookup_class(env, &ctx)?;
|
||||
HangupType::lookup_class(env, &ctx)?;
|
||||
HttpMethod::lookup_class(env, &ctx)?;
|
||||
CallEndReason::lookup_class(env, &ctx)?;
|
||||
ConnectionState::lookup_class(env, &ctx)?;
|
||||
JoinState::lookup_class(env, &ctx)?;
|
||||
SpeechEvent::lookup_class(env, &ctx)?;
|
||||
JBoolean::lookup_class(env, &ctx)?;
|
||||
JFloat::lookup_class(env, &ctx)?;
|
||||
JInteger::lookup_class(env, &ctx)?;
|
||||
JLong::lookup_class(env, &ctx)?;
|
||||
JArrayList::lookup_class(env, &ctx)?;
|
||||
JHashMap::lookup_class(env, &ctx)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -6,8 +6,8 @@
|
||||
//! webrtc::jni::JavaMediaStream Interface.
|
||||
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
objects::{GlobalRef, JObject},
|
||||
Env,
|
||||
objects::{Global, JObject},
|
||||
sys::jobject,
|
||||
};
|
||||
|
||||
@ -51,11 +51,11 @@ impl JavaMediaStream {
|
||||
Ok(Self { rffi })
|
||||
}
|
||||
|
||||
/// Return a JNI GlobalRef to the JavaMediaStream object
|
||||
pub fn global_ref(&self, env: &JNIEnv) -> Result<GlobalRef> {
|
||||
/// Return a JNI Global to the JavaMediaStream object
|
||||
pub fn global_ref(&self, env: &Env) -> Result<Global<JObject<'static>>> {
|
||||
unsafe {
|
||||
let object = Rust_getJavaMediaStreamObject(self.rffi.borrow());
|
||||
Ok(env.new_global_ref(JObject::from_raw(object))?)
|
||||
Ok(env.new_global_ref(JObject::from_raw(env, object))?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
//! Re-exports WebRTC JNI interfaces
|
||||
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
EnvUnowned,
|
||||
objects::{JClass, JObject},
|
||||
sys::jlong,
|
||||
};
|
||||
@ -17,7 +17,7 @@ unsafe extern "C" {
|
||||
/// Export the nativeCreatePeerConnection() call from the
|
||||
/// org.webrtc.PeerConnectionFactory class.
|
||||
pub fn Java_org_webrtc_PeerConnectionFactory_nativeCreatePeerConnection(
|
||||
env: JNIEnv,
|
||||
unowned_env: EnvUnowned,
|
||||
class: JClass,
|
||||
factory: jlong,
|
||||
rtcConfig: JObject,
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
//
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
//! Macros to generate JNI signature strings.
|
||||
//!
|
||||
//! Located outside of the `android` module so that the tests get run.
|
||||
|
||||
#![allow(unused_macros)]
|
||||
|
||||
/// Takes a Java-esque class name of the form `org.signal.Outer::Inner` and turns it into a
|
||||
/// JNI-style name `org/signal/Outer$Inner`.
|
||||
#[macro_export]
|
||||
macro_rules! jni_class_name {
|
||||
( $arg_base:tt $(. $arg_rest:ident)+ $(:: $arg_nested:ident)* ) => {
|
||||
concat!(
|
||||
stringify!($arg_base),
|
||||
$("/", stringify!($arg_rest),)+
|
||||
$("$", stringify!($arg_nested),)*
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jni_class_name() {
|
||||
assert_eq!(jni_class_name!(foo.bar), "foo/bar");
|
||||
assert_eq!(jni_class_name!(foo.bar.baz), "foo/bar/baz");
|
||||
assert_eq!(jni_class_name!(foo.bar.baz::garply), "foo/bar/baz$garply");
|
||||
assert_eq!(
|
||||
jni_class_name!(foo.bar.baz::garply::qux),
|
||||
"foo/bar/baz$garply$qux"
|
||||
);
|
||||
}
|
||||
|
||||
/// Converts a function or type signature to a JNI signature string.
|
||||
///
|
||||
/// This macro uses Rust function syntax `(Foo, Bar) -> Baz`, and uses Rust syntax for Java arrays
|
||||
/// `[Foo]`, but otherwise uses Java names for types: `boolean`, `byte`, `void`. Like
|
||||
/// [`jni_class_name`], inner classes are indicated with `::` rather than `.`.
|
||||
#[macro_export]
|
||||
macro_rules! jni_signature {
|
||||
( boolean ) => ("Z");
|
||||
( bool ) => (compile_error!("use Java type 'boolean'"));
|
||||
( byte ) => ("B");
|
||||
( char ) => ("C");
|
||||
( short ) => ("S");
|
||||
( int ) => ("I");
|
||||
( long ) => ("J");
|
||||
( float ) => ("F");
|
||||
( double ) => ("D");
|
||||
( void ) => ("V");
|
||||
|
||||
// Escape hatch: provide a literal string.
|
||||
( $x:literal ) => ($x);
|
||||
|
||||
// Arrays
|
||||
( [$($contents:tt)+] ) => {
|
||||
concat!("[", jni_signature!($($contents)+))
|
||||
};
|
||||
|
||||
// Classes
|
||||
( $arg_base:tt $(. $arg_rest:ident)+ $(:: $arg_nested:ident)* ) => {
|
||||
concat!(
|
||||
"L",
|
||||
jni_class_name!($arg_base $(. $arg_rest)+ $(:: $arg_nested)*),
|
||||
";"
|
||||
)
|
||||
};
|
||||
|
||||
// Functions
|
||||
(
|
||||
(
|
||||
$( $arg_base:tt $(. $arg_rest:ident)* $(:: $arg_nested:ident)* ),* $(,)?
|
||||
) -> $ret_base:tt $(. $ret_rest:ident)* $(:: $ret_nested:ident)*
|
||||
) => {
|
||||
concat!(
|
||||
"(",
|
||||
$( jni_signature!($arg_base $(. $arg_rest)* $(:: $arg_nested)*), )*
|
||||
")",
|
||||
jni_signature!($ret_base $(. $ret_rest)* $(:: $ret_nested)*)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jni_signature() {
|
||||
// Literals
|
||||
assert_eq!(jni_signature!("Lfoo/bar;"), "Lfoo/bar;");
|
||||
|
||||
// Classes
|
||||
assert_eq!(jni_signature!(foo.bar), "Lfoo/bar;");
|
||||
assert_eq!(jni_signature!(foo.bar.baz), "Lfoo/bar/baz;");
|
||||
assert_eq!(jni_signature!(foo.bar.baz::garply), "Lfoo/bar/baz$garply;");
|
||||
assert_eq!(
|
||||
jni_signature!(foo.bar.baz::garply::qux),
|
||||
"Lfoo/bar/baz$garply$qux;"
|
||||
);
|
||||
|
||||
// Arrays
|
||||
assert_eq!(jni_signature!([byte]), "[B");
|
||||
assert_eq!(jni_signature!([[byte]]), "[[B");
|
||||
assert_eq!(jni_signature!([foo.bar]), "[Lfoo/bar;");
|
||||
assert_eq!(
|
||||
jni_signature!([foo.bar.baz::garply::qux]),
|
||||
"[Lfoo/bar/baz$garply$qux;"
|
||||
);
|
||||
|
||||
// Functions
|
||||
assert_eq!(jni_signature!(() -> void), "()V");
|
||||
assert_eq!(jni_signature!((byte, int) -> float), "(BI)F");
|
||||
assert_eq!(
|
||||
jni_signature!(([byte], foo.bar, foo.bar.baz::garply::qux) -> [byte]),
|
||||
"([BLfoo/bar;Lfoo/bar/baz$garply$qux;)[B"
|
||||
);
|
||||
assert_eq!(jni_signature!(() -> foo.bar), "()Lfoo/bar;");
|
||||
assert_eq!(
|
||||
jni_signature!(() -> foo.bar.baz::garply::qux),
|
||||
"()Lfoo/bar/baz$garply$qux;"
|
||||
);
|
||||
}
|
||||
@ -6,7 +6,6 @@
|
||||
//! Common types used throughout the library.
|
||||
|
||||
pub mod actor;
|
||||
pub mod jni_signature;
|
||||
pub mod slice;
|
||||
pub mod time;
|
||||
pub mod units;
|
||||
|
||||
@ -70,6 +70,7 @@ mod android {
|
||||
mod call_manager;
|
||||
mod error;
|
||||
mod logging;
|
||||
mod types;
|
||||
mod webrtc_java_media_stream;
|
||||
mod webrtc_peer_connection_factory;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user