Android's SSLServerSocket causes increasing native memory in the App, OOM -


background

i developing android app provides simple http/https server. if https serving configured on every connection increasing native memory usage observed leads app crash (oom), while using http configuration keeps native memory usage relative constant. app's java vm keeps relative constant in both configurations.

the app serves html page contains javascript periodic polling (one json poll every second), calling app page using https configuration , keeping page open several hours lead mentioned out-of-memory because of increasing native memory usage. have tested many sslserversocket , sslcontext configurations found on internet no luck.

i observe same problem on various android devices , various android versions beginning 2.2 4.3.

the code handling client requests same both configurations http/https. difference between 2 configurations setup of server socket. while in case of http server socket 1 single line similar "serversocket serversocket = new serversocket(myport);" job, in case of https server setup usual steps setting sslcontext taken -- i.e. setting keymanager , initializing sslcontext. now, use default trustmanager.

need advice

does know memory leak problems in android's default tls provider using openssl? there special should consider avoid leak in native memory? hint highly appreciated.

update: have tried both tls providers: openssl , jsse explicitly giving provider name in sslcontext.getinstance( "tls", providername ). did not change anything.

here code block demonstrates problem. create sample app put bottom of main activity's oncreate , build & run app. make sure wifi on , call html page following address:

https://android device ip:9090 

then watch adb logs, after while see native memory beginning increase.

 new thread(new runnable() {

public void run() {

final int port = 9090; sslcontext sslcontext = sslcontext.getinstance( "tls" ); // jsse , openssl providers behave same way keymanagerfactory kmf = keymanagerfactory.getinstance( keymanagerfactory.getdefaultalgorithm() ); keystore ks = keystore.getinstance( keystore.getdefaulttype() ); char[] password = keystore_pw.tochararray(); // assume keystore in app assets inputstream sslkeystore = getapplicationcontext().getresources().openrawresource( r.raw.keystore ); ks.load( sslkeystore, null ); sslkeystore.close(); kmf.init( ks, password ); sslcontext.init( kmf.getkeymanagers(), null, new securerandom() ); serversocketfactory ssf = sslcontext.getserversocketfactory(); sslcontext.getserversessioncontext().setsessiontimeout(5); try { sslserversocket serversocket = ( sslserversocket )ssf.createserversocket(port); // alternatively, plain server socket can created here //serversocket serversocket = new serversocket(9090); serversocket.setreceivebuffersize( 8192 ); int num = 0; long lastnatmem = 0, natmemtotalincrease = 0; while (true) { try { socket soc = (socket) serversocket.accept(); log.i(tag, "client connected (" + num++ + ")"); soc.setsotimeout(2000); try { sslsession session = ((sslsocket)soc).getsession(); boolean valid = session.isvalid(); log.d(tag, "session valid: " + valid); outputstream os = null; inputstream = null; try { os = soc.getoutputstream(); // read complete request client = soc.getinputstream(); int c = 0; string itext = ""; while ( (c = is.read() ) > 0 ) { itext += (char)c; if (itext.contains("\r\n\r\n")) // end of request detection break; } //log.e(tag, " req: " + itext); } catch (sockettimeoutexception e) { // can happen (handshake timeout) log.d(tag, "socket timeout: " + e.getmessage()); if (os != null) os.close(); if (is != null) is.close(); soc.close(); continue; } long natmem = debug.getnativeheapsize(); long diff = 0; if (lastnatmem != 0) { diff = natmem - lastnatmem; natmemtotalincrease += diff; } lastnatmem = natmem; log.i(tag, " answer request, native memory in use: " + natmem / 1024 + ", diff: " + diff / 1024 + ", total increase: " + natmemtotalincrease / 1024); string html = "<!doctype html><html><head>"; html += "<script type='text/javascript'>"; html += "function poll() { request(); window.settimeout(poll, 1000);}\n"; html += "function request() { var xmlhttp = new xmlhttprequest(); xmlhttp.open( \"get\", \"/\", false ); xmlhttp.send( null ); return xmlhttp.responsetext; }"; html += "</script>"; html += "</head><body onload=\"poll()\"><p>refresh site see inreasing native memory when using https: " + natmem + " </p></body></html> "; byte[] buffer = html.getbytes("utf-8"); printwriter pw = new printwriter( os ); pw.print("http/1.0 200 ok \r\n"); pw.print("content-type: text/html\r\n"); pw.print("content-length: " + buffer.length + "\r\n"); pw.print("\r\n"); pw.flush(); os.write(buffer); os.flush(); os.close(); } catch (ioexception e) { e.printstacktrace(); } soc.close(); } catch (ioexception e) { e.printstacktrace(); } } } catch (socketexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } } }).start();

-- edit --

i have uploaded sample app project called ssltest eclipse demonstrates problem:

http://code.google.com/p/android/issues/detail?id=59536

-- update --

good news: today reported android issue above identified , proper submissions made fix memory leak. more details see link above.

i imagine substantial time investment, see valgrind has been ported android. try getting , running. of course, if find there's internal memory leak, there isn't lot can except attempt bug fixed in future android releases.

as workaround, make application multi-process , put https service in separate process. way restart periodically, avoiding oom. might have have third process accepting port 443 connections , passing them on https worker - in order avoid tiny outages when https worker restarted.

this sounds substantial time investment :) presumably avoid problem.

--- edit: more detail ---

yes, if have main application own ui, worker process handling ssl , worker process accepting ssl requests (which can't 443), on top of normal activity classes, have 2 service classes, , manifest place them in separate processes.

handling ssl process: rather waiting oom crash service, service monitor own debug.getnativeheapsize(), , explicitly restart service when increased much. either that, or restart automatically after every 100 requests or so.

handling listening socket process: service listen on tcp port choose , pass on raw data ssl process. bit needs thought, obvious solution have ssl process listen on different local port x (or switch between selection of different ports), , listening socket process forward data port x. reason having listening socket process gracefully handle possibility x down - might whenever restart it.

if requirements allow there being occasional mini-outages handling ssl process, , skip listening socket process, it's relatively simple solution - not different you'd normally. it's listening socket process adds complexity solution...


Comments

Popular posts from this blog

Unable to remove the www from url on https using .htaccess -