From f208b04658b975b56652d4166c1b2be8cda25454 Mon Sep 17 00:00:00 2001 From: Jose Date: Thu, 9 Jan 2025 17:47:41 +0100 Subject: [PATCH] Avoid doing IO operations on Android main thread --- .../java/com/zeroc/hello/DeliveryMode.java | 48 -------------- .../main/java/com/zeroc/hello/HelloApp.java | 63 +++++++++++-------- .../main/java/com/zeroc/hello/HelloWorld.java | 18 +++++- 3 files changed, 51 insertions(+), 78 deletions(-) diff --git a/java/android/hello/src/main/java/com/zeroc/hello/DeliveryMode.java b/java/android/hello/src/main/java/com/zeroc/hello/DeliveryMode.java index cf22a6972a..62a9c82445 100644 --- a/java/android/hello/src/main/java/com/zeroc/hello/DeliveryMode.java +++ b/java/android/hello/src/main/java/com/zeroc/hello/DeliveryMode.java @@ -17,54 +17,6 @@ enum DeliveryMode DATAGRAM, DATAGRAM_BATCH; - ObjectPrx apply(ObjectPrx prx) - { - switch (this) - { - case TWOWAY: - { - prx = prx.ice_twoway(); - break; - } - case TWOWAY_SECURE: - { - prx = prx.ice_twoway().ice_secure(true); - break; - } - case ONEWAY: - { - prx = prx.ice_oneway(); - break; - } - case ONEWAY_BATCH: - { - prx = prx.ice_batchOneway(); - break; - } - case ONEWAY_SECURE: - { - prx = prx.ice_oneway().ice_secure(true); - break; - } - case ONEWAY_SECURE_BATCH: - { - prx = prx.ice_batchOneway().ice_secure(true); - break; - } - case DATAGRAM: - { - prx = prx.ice_datagram(); - break; - } - case DATAGRAM_BATCH: - { - prx = prx.ice_batchDatagram(); - break; - } - } - return prx; - } - public boolean isOneway() { return this == ONEWAY || this == ONEWAY_SECURE || this == DATAGRAM; diff --git a/java/android/hello/src/main/java/com/zeroc/hello/HelloApp.java b/java/android/hello/src/main/java/com/zeroc/hello/HelloApp.java index cfc1d28448..00ac2c2ea5 100644 --- a/java/android/hello/src/main/java/com/zeroc/hello/HelloApp.java +++ b/java/android/hello/src/main/java/com/zeroc/hello/HelloApp.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @@ -91,8 +92,6 @@ else if(m.what == MSG_EXCEPTION || m.what == MSG_RESPONSE) { InitializationData initData = new InitializationData(); - initData.executor = (Runnable runnable, Connection connection) -> _uiHandler.post(runnable); - initData.properties = new Properties(); initData.properties.setProperty("Ice.Trace.Network", "3"); @@ -104,18 +103,23 @@ else if(m.what == MSG_EXCEPTION || m.what == MSG_RESPONSE) KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(getResources().openRawResource(R.raw.client), "password".toCharArray()); + // Create a key manager manager factory that uses the certificates from our KeyStore. + KeyManagerFactory keyManagerFactory = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, "password".toCharArray()); + // Create a trust manager factory that uses the certificates from our KeyStore. TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); // Create a SSLContext for TLS and initialize it with our custom trust manager factory. var sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); // Setup the SSLEngine factory used by secure (TLS) client connections. initData.clientSSLEngineFactory = - (String peerHost, int peerPort) -> sslContext.createSSLEngine(peerHost, peerPort); + (String peerHost, int peerPort) -> sslContext.createSSLEngine(peerHost, peerPort); Communicator c = Util.initialize(initData); _uiHandler.sendMessage(Message.obtain(_uiHandler, MSG_READY, new MessageReady(c, null))); @@ -127,9 +131,9 @@ else if(m.what == MSG_EXCEPTION || m.what == MSG_RESPONSE) catch (Exception e) { _uiHandler.sendMessage(Message.obtain( - _uiHandler, - MSG_READY, - new MessageReady(null, new InitializationException("Communicator initialization failed", e)))); + _uiHandler, + MSG_READY, + new MessageReady(null, new InitializationException("Communicator initialization failed", e)))); } }).start(); } @@ -216,10 +220,8 @@ void shutdown() try { updateProxy(); - if(_proxy == null) - { - return; - } + assert(_proxy != null); + _proxy.shutdownAsync().whenComplete((result, ex) -> { if(ex != null) @@ -245,7 +247,9 @@ void shutdownAsync() try { updateProxy(); - if(_proxy == null || _result != null) + assert (_proxy != null); + + if(_result != null) { return; } @@ -322,7 +326,9 @@ void sayHelloAsync(int delay) try { updateProxy(); - if(_proxy == null || _result != null) + assert(_proxy != null); + + if(_result != null) { return; } @@ -374,23 +380,26 @@ private void updateProxy() return; } - String s; - if(_useDiscovery) - { - s = "hello"; - } - else - { - s = "hello:tcp -h " + _host + " -p 10000:ssl -h " + _host + " -p 10001:udp -h " + _host + " -p 10000"; - } - ObjectPrx prx = _communicator.stringToProxy(s); - prx = _mode.apply(prx); + var prx = HelloPrx.createProxy( + _communicator, + _useDiscovery ? "hello" : "hello:tcp -h " + _host + " -p 10000:ssl -h " + _host + " -p 10001:udp -h " + _host + " -p 10000"); + + prx = switch (_mode) { + case TWOWAY -> prx.ice_twoway(); + case TWOWAY_SECURE -> prx.ice_twoway().ice_secure(true); + case ONEWAY -> prx.ice_oneway(); + case ONEWAY_BATCH -> prx.ice_batchOneway(); + case ONEWAY_SECURE -> prx.ice_oneway().ice_secure(true); + case ONEWAY_SECURE_BATCH -> prx.ice_batchOneway().ice_secure(true); + case DATAGRAM -> prx.ice_datagram(); + case DATAGRAM_BATCH -> prx.ice_batchDatagram(); + }; + if(_timeout != 0) { prx = prx.ice_invocationTimeout(_timeout); } - - _proxy = HelloPrx.uncheckedCast(prx); + _proxy = prx; } DeliveryMode getDeliveryMode() diff --git a/java/android/hello/src/main/java/com/zeroc/hello/HelloWorld.java b/java/android/hello/src/main/java/com/zeroc/hello/HelloWorld.java index e965f978f4..027cd105c1 100644 --- a/java/android/hello/src/main/java/com/zeroc/hello/HelloWorld.java +++ b/java/android/hello/src/main/java/com/zeroc/hello/HelloWorld.java @@ -32,6 +32,8 @@ import com.zeroc.Ice.LocalException; +import java.util.concurrent.ExecutorService; + public class HelloWorld extends AppCompatActivity { public static class ErrorDialogFragment extends DialogFragment @@ -109,6 +111,7 @@ public void onCreate(Bundle savedInstanceState) final SharedPreferences prefs = getPreferences(MODE_PRIVATE); _app = (HelloApp)getApplication(); + _executor = java.util.concurrent.Executors.newSingleThreadExecutor(); useDiscoveryCheckBox.setOnClickListener(v -> { final boolean checked = ((CheckBox)v).isChecked(); @@ -139,7 +142,11 @@ public void onCreate(Bundle savedInstanceState) } else { - _app.sayHelloAsync(delaySeekBar.getProgress()); + int delay = delaySeekBar.getProgress(); + // sayHelloAsync is called on the executor to avoid IO operations on the main thread. + _executor.execute(() -> { + _app.sayHelloAsync(delay); + }); } }); @@ -152,7 +159,10 @@ public void onCreate(Bundle savedInstanceState) } else { - _app.shutdownAsync(); + // shutdownAsync is called on the executor to avoid IO operations on the main thread. + _executor.execute(() -> { + _app.shutdownAsync(); + }); } }); @@ -199,7 +209,8 @@ public void onTextChanged(CharSequence s, int start, int count, int after) }); flushButton.setOnClickListener(v -> { - _app.flush(); + // flush is called on the executor to avoid IO operations on the main thread. + _executor.execute(() -> _app.flush()); flushButton.setEnabled(false); statusTextView.setText(R.string.flushed_batch_requests); }); @@ -413,5 +424,6 @@ protected void onDestroy() private static final String BUNDLE_KEY_FLUSH_ENABLED = "zeroc:flush"; private HelloApp _app; + private ExecutorService _executor; private Handler _handler; }