Skip to content

Commit

Permalink
Use efficient operations when copying bytes between Dart and Java (#1019
Browse files Browse the repository at this point in the history
)
  • Loading branch information
brianquinlan authored Sep 14, 2023
1 parent d7e4375 commit e19094a
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 1,439 deletions.
4 changes: 4 additions & 0 deletions pkgs/cronet_http/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.4.0-jni

* Use more efficient operations when copying bytes between Java and Dart.

## 0.3.0-jni

* Switch to using `package:jnigen` for bindings to Cronet
Expand Down
10 changes: 10 additions & 0 deletions pkgs/cronet_http/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ android {
defaultConfig {
minSdkVersion 16
}

defaultConfig {
consumerProguardFiles 'consumer-rules.pro'
}

buildTypes {
release {
minifyEnabled false
}
}
}

dependencies {
Expand Down
1 change: 1 addition & 0 deletions pkgs/cronet_http/android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-keep class io.flutter.plugins.cronet_http.** { *; }
3 changes: 3 additions & 0 deletions pkgs/cronet_http/example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,7 @@ flutter {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// ""com.google.android.gms:play-services-cronet" is only present so that
// `jnigen` will work. Applications should not include this line.
implementation "com.google.android.gms:play-services-cronet:18.0.1"
}
4 changes: 0 additions & 4 deletions pkgs/cronet_http/jnigen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ android_sdk_config:
add_gradle_deps: true
android_example: 'example/'

suspend_fun_to_async: true

output:
bindings_type: dart_only
dart:
Expand All @@ -18,8 +16,6 @@ output:
classes:
- 'io.flutter.plugins.cronet_http.UrlRequestCallbackProxy'
- 'java.net.URL'
- 'java.nio.Buffer'
- 'java.nio.ByteBuffer'
- 'java.util.concurrent.Executors'
- 'org.chromium.net.CronetEngine'
- 'org.chromium.net.CronetException'
Expand Down
28 changes: 9 additions & 19 deletions pkgs/cronet_http/lib/src/cronet_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
library;

import 'dart:async';
import 'dart:typed_data';

import 'package:http/http.dart';
import 'package:jni/jni.dart';

import 'jni/jni_bindings.dart' as jb;

final _digitRegex = RegExp(r'^\d+$');
const _bufferSize = 10 * 1024; // The size of the Cronet read buffer.

/// The type of caching to use when making HTTP requests.
enum CacheMode {
Expand Down Expand Up @@ -138,7 +138,7 @@ Map<String, String> _cronetToClientHeaders(
jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface _urlRequestCallbacks(
BaseRequest request, Completer<StreamedResponse> responseCompleter) {
StreamController<List<int>>? responseStream;
jb.ByteBuffer? byteBuffer;
JByteBuffer? jByteBuffer;
var numRedirects = 0;

// The order of callbacks generated by Cronet is documented here:
Expand Down Expand Up @@ -175,8 +175,8 @@ jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface _urlRequestCallbacks(
headers: responseHeaders,
));

byteBuffer = jb.ByteBuffer.allocateDirect(1024 * 1024);
urlRequest.read(byteBuffer!);
jByteBuffer = JByteBuffer.allocateDirect(_bufferSize);
urlRequest.read(jByteBuffer!);
},
onRedirectReceived: (urlRequest, responseInfo, newLocationUrl) {
if (!request.followRedirects) {
Expand Down Expand Up @@ -204,20 +204,15 @@ jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface _urlRequestCallbacks(
},
onReadCompleted: (urlRequest, responseInfo, byteBuffer) {
byteBuffer.flip();
responseStream!
.add(jByteBuffer!.asUint8List().sublist(0, byteBuffer.remaining));

final remaining = byteBuffer.remaining();
final data = Uint8List(remaining);
// TODO: Use a more efficient approach when
// https://github.com/dart-lang/jnigen/issues/387 is fixed.
for (var i = 0; i < remaining; ++i) {
data[i] = byteBuffer.get1(i);
}
responseStream!.add(data);
byteBuffer.clear();
urlRequest.read(byteBuffer);
},
onSucceeded: (urlRequest, responseInfo) {
responseStream!.sink.close();
jByteBuffer?.release();
},
onFailed: (urlRequest, responseInfo, cronetException) {
final error = ClientException(
Expand All @@ -228,6 +223,7 @@ jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface _urlRequestCallbacks(
responseStream!.addError(error);
responseStream!.close();
}
jByteBuffer?.release();
},
));
}
Expand Down Expand Up @@ -333,14 +329,8 @@ class CronetClient extends BaseClient {
headers.forEach((k, v) => builder.addHeader(k.toJString(), v.toJString()));

if (body.isNotEmpty) {
// TODO: Use a more efficient approach when
// https://github.com/dart-lang/jnigen/issues/387 is fixed.
final bodyBytes = JArray(jbyte.type, body.length);
for (var i = 0; i < body.length; ++i) {
bodyBytes[i] = body[i];
}
builder.setUploadDataProvider(
jb.UploadDataProviders.create4(bodyBytes), _executor);
jb.UploadDataProviders.create2(body.toJByteBuffer()), _executor);
}
builder.build().start();
return responseCompleter.future;
Expand Down
Loading

0 comments on commit e19094a

Please sign in to comment.