custom-cert-https icon indicating copy to clipboard operation
custom-cert-https copied to clipboard

getAcceptedIssuers on system trust manager very slow

Open foens opened this issue 11 years ago • 4 comments

Hi there.

I have used your idea of creating a combined TrustManager which you call MyTrustManager.

However, when instantiating MyTrustManager, then the defaultTrustManager's accepted issuers is combined with the local one in this code:

List<X509Certificate> allIssuers = new ArrayList<X509Certificate>();
for (X509Certificate cert : defaultTrustManager.getAcceptedIssuers()) {
   allIssuers.add(cert);
}
for (X509Certificate cert : localTrustManager.getAcceptedIssuers()) {
    allIssuers.add(cert);
}
acceptedIssuers = allIssuers.toArray(new X509Certificate[allIssuers.size()]);

However, the call to defaultTrustManager.getAcceptedIssuers() is very slow (5-15sec) on the Android platform (at least on my phone).

In my instance, the Apache HttpClient never calls getAcceptedIssuers() and therefore the work is wasted.

I rewrote the implementation to prepare the list only if getAcceptedIssuers() was called:

public X509Certificate[] getAcceptedIssuers() {
    Log.d(TAG, "getAcceptedIssuers()...");
    if(acceptedIssuers == null) {
        synchronized(this) {
            if(acceptedIssuers == null) {
                List<X509Certificate> allIssuers = new ArrayList<X509Certificate>();
                Collections.addAll(allIssuers, defaultTrustManager.getAcceptedIssuers());
                Collections.addAll(allIssuers, localTrustManager.getAcceptedIssuers());
                acceptedIssuers = allIssuers.toArray(new X509Certificate[allIssuers.size()]);
            }
        }
    }
    return acceptedIssuers;
}

It is exactly as slow as your implementation, but if it is not called, the list will not be prepared. Also notice that I used the Collections.addAll utility methods instead of the for loops. It uses the singleton pattern as described on stackoverflow. http://stackoverflow.com/a/11165926/477854

I hope you will incorporate these changes such that other people will not have to deal with this problem.

foens avatar Feb 04 '14 11:02 foens

What phone and Android version are you using? Can you profile the method and find out which part is slow?

nelenkov avatar Feb 04 '14 13:02 nelenkov

HTC One S (Android 4.1.1). I used a debugger and the getAcceptedIssuers() was the problem. I moved it outside the loop and only fetched it into a variable.

foens avatar Feb 04 '14 14:02 foens

That method does a few things, you need to log how much time each call takes to get an idea what is causing the slowness. The debugger slows things down considerably, so it's not very helpful for profiling.

nelenkov avatar Feb 04 '14 14:02 nelenkov

I know. Which method are you talking about. The getAcceptedIssuers() of defaultTrustManager? The timings i gave (5-15 sec) was approximately how it felt for the user. When using the debugger, the times where much more in the range 50sec to 90 sec. Want me to debug getAcceptedIssusers()? (btw, leaving work at this moment)

foens avatar Feb 04 '14 14:02 foens