firebase-android-sdk
firebase-android-sdk copied to clipboard
FirebaseRemoteConfigClientException The client had an error while calling the backend!
Hi @jamesdaniels
i have issue with FirebaseRemoteConfig, below is the image which I added SSL certificate for api calling is not working in android 5.0 and 6.0 because of https issue, so i added this SSL self trust manager in my app and api calling is working in all device by Firebase remote config not working,
implementation platform('com.google.firebase:firebase-bom:29.0.3')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-crashlytics-ktx'
implementation 'com.google.firebase:firebase-config-ktx'
and here is FirebaseRemotoConfig code to get value from Firebase Remote config, i am getting error like this com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException: The client had an error while calling the backend!
I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
Hi @GauravCreed, thanks for reporting with code snippets. Could you could provide us more stacktrace and an MCVE of your issue? It'll greatly help with the investigation. Thanks!
Just adding notes here:
It looks like it's causing the issue in the fetch
method in ConfigFetchHttpClient.java
And around this line https://github.com/firebase/firebase-android-sdk/blob/275b3eb9940f64c25ae614f75a4fd5f04eb09625/firebase-config/src/main/java/com/google/firebase/remoteconfig/internal/ConfigFetchHttpClient.java#L199-L202
Hi @argzdev
i got this exception because , I am adding android:networkSecurityConfig="@xml/network_security_config"
this SSL self sign certificate, if remove this line from manifest file then firebase config working well and fetching all value from FirebaseRemoteConfig,
in my app this is require because https is compulsory in URL with api calling, so added https in api calling URL and add this on manifest file, so app is working in android 7.0 OS also otherwise it will not work.
So my question is how can we achieve both,? is there any conflict with SSL certificate with FirebaseRemoteConfig?
Thanks(_) .
Thanks for the extra details @GauravCreed. I was able to repro the same issue.
In my case, I experience the issue when I include the relevant code you've provided for allowmySSL()
. If I choose to only use @xml/network_security_config.xml without the allowMySSL()
method, it works properly. However I don't think this is what you want.
Another thing I've noticed with your setup is if you call an API before Firebase Remote Config, the API would succeed but Firebase Remote Config would fail. However when opposite is applied, if I choose to call Firebase Remote Config first, and then the API, both succeeds, which seems to me is like a race condition issue. Perhaps, an alternative solution you could try is calling remote config before your API calls while we investigate this further.
Since I was able to repro this issue, I'll notify an engineer and see what we can do here.
FWIW, Here is my relevant code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_server = findViewById(R.id.tv_server);
tv_remote = findViewById(R.id.tv_remote);
callRemoteConfig();
callRequestHttps();
}
private SSLSocketFactory allowSSL(){
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.cert);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
SSLSocketFactory sf = context.getSocketFactory();
return sf;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void callRequestHttps(){
RequestQueue queue = Volley.newRequestQueue(this, new HurlStack(null, allowSSL()));
String url ="https://10.0.2.2:3443";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
response -> tv_server.setText(response),
error -> tv_server.setText("That didn't work! " + error.getMessage())
);
queue.add(stringRequest);
}
private void callRemoteConfig(){
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
.setMinimumFetchIntervalInSeconds(3600)
.build();
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
mFirebaseRemoteConfig.setConfigSettingsAsync(configSettings);
mFirebaseRemoteConfig.setDefaultsAsync(R.xml.remote_config_defaults);
tv_remote.setText(mFirebaseRemoteConfig.getString("random_value"));
mFirebaseRemoteConfig.fetchAndActivate()
.addOnCompleteListener(this, task -> {
if (task.isSuccessful()) {
boolean updated = task.getResult();
Log.d(TAG, "Config params updated: " + updated);
Toast.makeText(MainActivity.this, "Fetch and activate succeeded", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Fetch failed " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
displayWelcomeMessage();
});
}
Hi @argzdev
Thanks for accepting that issue is occurring due to SSL Socket Exception, and again thanks for giving the solution hint, I think it's wont work because, allowSSL(); I called in my app Application class and Firebase Remote Config is added when I used this data,
so basically the allowSSL() proceed first, my app need api calling in so many classis that is the reason why I am using this method in my Application class.
Again Thanks. if possible with other solution then pls share with us.
Thanks for the extra details, @GauravCreed. We created an internal bug b/216826260, we'll reply here when we have updates. Thanks!
I have not added any Custom SSL certificates, yet, I am getting this exact exception. I narrowed down the problem to this exception: javax.net.ssl.SSLHandshakeException: SSL handshake aborted: ssl=0xd5561908: I/O error during system call, Connection reset by peer
This happens in the file ConfigFetchHttpClient.java in the catch block in fetch() method. The url is that firebase is trying to hit is: https://firebaseremoteconfig.googleapis.com/v1/projects/98058910649/namespaces/firebase:fetch
Here is the stacktrace
0 = {StackTraceElement@15324} "com.google.android.gms.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)"
1 = {StackTraceElement@15325} "com.google.android.gms.org.conscrypt.NativeSsl.doHandshake(:com.google.android.gms@[email protected] (100700-441847897):6)"
2 = {StackTraceElement@15326} "com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(:com.google.android.gms@[email protected] (100700-441847897):16)"
3 = {StackTraceElement@15327} "com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:196)"
4 = {StackTraceElement@15328} "com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:153)"
5 = {StackTraceElement@15329} "com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)"
6 = {StackTraceElement@15330} "com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)"
7 = {StackTraceElement@15331} "com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)"
8 = {StackTraceElement@15332} "com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)"
9 = {StackTraceElement@15333} "com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)"
10 = {StackTraceElement@15334} "com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)"
11 = {StackTraceElement@15335} "com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)"
12 = {StackTraceElement@15336} "com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)"
13 = {StackTraceElement@15337} "com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262)"
14 = {StackTraceElement@15338} "com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219)"
15 = {StackTraceElement@15339} "com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30)"
16 = {StackTraceElement@15340} "com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient.setFetchRequestBody(ConfigFetchHttpClient.java:364)"
17 = {StackTraceElement@15341} "com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient.fetch(ConfigFetchHttpClient.java:196)"
18 = {StackTraceElement@15342} "com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackend(ConfigFetchHandler.java:312)"
19 = {StackTraceElement@15343} "com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackendAndCacheResponse(ConfigFetchHandler.java:283)"
20 = {StackTraceElement@15344} "com.google.firebase.remoteconfig.internal.ConfigFetchHandler.lambda$fetchIfCacheExpiredAndNotThrottled$1$ConfigFetchHandler(ConfigFetchHandler.java:220)"
21 = {StackTraceElement@15345} "com.google.firebase.remoteconfig.internal.-$$Lambda$ConfigFetchHandler$PAoFtfQiOtbXSTeK4H2aFJ-JNJI.then(Unknown Source:8)"
22 = {StackTraceElement@15346} "com.google.android.gms.tasks.zze.run(com.google.android.gms:play-services-tasks@@18.0.1:1)"
23 = {StackTraceElement@15347} "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)"
24 = {StackTraceElement@15348} "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)"
25 = {StackTraceElement@15349} "java.lang.Thread.run(Thread.java:919)"
Hi @argzdev
I think we found solution for this, but don't know this is right or wrong.
1 - Add https in all api url 2 - Change minSdkVersion to 24 3 - Update in manifest file usesCleartextTraffic to true 4 - Add below method when you called api and check url is correct or not
public static String getCorrectURL(String url) { if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) return url.replace("https", "http"); return url; }
Pls. suggest me if this is right process or not, i have made this solution for my app.
Hi @GauravCreed, I'm glad you were able to find a solution for your issue.
1 - Add https in all api url
Using "https" for all your API calls is definitely a good thing in terms of security.
2 - Change minSdkVersion to 24
This should be okay to do.
4 - Add below method when you called api and check url is correct or not
This seems a bit counterproductive, since you've setup all APIs as https, and yet you're replacing them on your getCorrectURL
.
3 - Update in manifest file usesCleartextTraffic to true
In the Android official docs, android:usesCleartextTraffic
: indicates whether the app intends to use cleartext network traffic, such as cleartext HTTP. The default value for apps that target API level 27 or lower is "true". Apps that target API level 28 or higher default to "false".
There hasn't been any update yet on the bug ticket. And unfortunately, there's no officially recommended solution yet for this use case.
However, I do think that if this works for you and it should be fine. As long as you know the security issue this may present. In the Android official docs, "The key reason for avoiding cleartext traffic is the lack of confidentiality, authenticity, and protections against tampering; a network attacker can eavesdrop on transmitted data and also modify it without being detected."
It seems to me that this question/issue has been resolved. That said, I'll be closing this now. Thanks!