summaryrefslogtreecommitdiff
path: root/telecomm/java
diff options
context:
space:
mode:
author Tyler Gunn <tgunn@google.com> 2025-03-18 17:10:43 +0000
committer Tyler Gunn <tgunn@google.com> 2025-03-18 17:21:28 +0000
commitf0d6e1c56fc11c26c51d17c10e62ae27e5733731 (patch)
tree9a0f8b35a8dd4c18e4aeefe34236ccffda8435e1 /telecomm/java
parentc0e04bd27ce7550e4e557477b51241ea76001b0a (diff)
Catch exceptions when comparing bundles.
We tried to catch ClassCastException in the past and log the key in question so we could determine the root cause. It looks like in the end this is likely a concurrent access issue where the InCallService is trying to modify the bundle while Telecom is updating it. This is not something that happens often. Rather than taking the performance hit of copying the Bundle in the get, or sychronizing, we'll just catch and assume the Bundles are not equal. Worst case we end up triggering an extra Call.Callback#onDetailsChanged signal to the ICS. Test: Run unit tests. Flag: NONE Crash fix. Fixes: 404168135 Change-Id: I5bc7a2170701fda364f6c4ca19d82a4c46745792
Diffstat (limited to 'telecomm/java')
-rw-r--r--telecomm/java/android/telecom/Call.java60
1 files changed, 35 insertions, 25 deletions
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c244168c65fd..51ce144881b7 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2912,38 +2912,48 @@ public final class Call {
if (bundle.size() != newBundle.size()) {
return false;
}
-
- for(String key : bundle.keySet()) {
- if (key != null) {
- if (!newBundle.containsKey(key)) {
- return false;
- }
- // In case new call extra contains non-framework class objects, return false to
- // force update the call extra
- try {
- final Object value = bundle.get(key);
- final Object newValue = newBundle.get(key);
- if (value instanceof Bundle && newValue instanceof Bundle) {
- if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) {
- return false;
- }
+ try {
+ for (String key : bundle.keySet()) {
+ if (key != null) {
+ if (!newBundle.containsKey(key)) {
+ return false;
}
- if (value instanceof byte[] && newValue instanceof byte[]) {
- if (!Arrays.equals((byte[]) value, (byte[]) newValue)) {
+ // In case new call extra contains non-framework class objects, return false to
+ // force update the call extra
+ try {
+ final Object value = bundle.get(key);
+ final Object newValue = newBundle.get(key);
+ if (value instanceof Bundle && newValue instanceof Bundle) {
+ if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) {
+ return false;
+ }
+ }
+ if (value instanceof byte[] && newValue instanceof byte[]) {
+ if (!Arrays.equals((byte[]) value, (byte[]) newValue)) {
+ return false;
+ }
+ } else if (!Objects.equals(value, newValue)) {
return false;
}
- } else if (!Objects.equals(value, newValue)) {
+ } catch (BadParcelableException e) {
return false;
}
- } catch (BadParcelableException e) {
- return false;
- } catch (ClassCastException e) {
- Log.e(LOG_TAG, e, "areBundlesEqual: failure comparing bundle key %s", key);
- // until we know what is causing this, we should rethrow -- this is still not
- // expected.
- throw e;
}
}
+ } catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
+ // Unfortunately this may get raised when accessing the bundle's keyset, so we cannot
+ // determine WHY a class cast exception is happening. We had tried in the past to do
+ // this down in the for loop so we could figure out which key is causing an issue.
+ // Bundles are not thread safe, so the most likely issue here is that the InCallService
+ // implementation is accessing the Bundle WHILE an incoming Telecom update comes in to
+ // potentially replace the Bundle. We call "areBundlesEqual" to see if the newly
+ // unparceled Call.Details is the same as what is already in the current Call instance.
+ // If those two operations overleave, I can see the potential for concurrent
+ // modification and edit of the Bundle. So we'll just catch here and assume the Bundles
+ // are not the same. This means a Call.CallBack may fire the onCallDetails changed
+ // callback when the Bundle didn't actually change.
+ Log.e(LOG_TAG, e, "areBundlesEqual: failed!");
+ return false;
}
return true;
}