diff options
author | Joachim Sauer <jsauer@google.com> | 2016-08-18 12:26:39 +0100 |
---|---|---|
committer | Joachim Sauer <jsauer@google.com> | 2016-08-19 11:18:50 +0100 |
commit | 35a16e21d16dd42c7ff7cd5a4e0976206522897c (patch) | |
tree | 8f2cebb7f71b53f3f234ec631a150f7b3fd41e84 | |
parent | 77fddf01ddabd0a77745d1b902badf51901e9077 (diff) | |
download | android_external_icu-35a16e21d16dd42c7ff7cd5a4e0976206522897c.tar.gz android_external_icu-35a16e21d16dd42c7ff7cd5a4e0976206522897c.tar.bz2 android_external_icu-35a16e21d16dd42c7ff7cd5a4e0976206522897c.zip |
Fix deadlock between java.util and ICU TimeZone.
There was a deadlock between java.util.TimeZone.setDefault() and
android.icu.util.TimeZone.getDefault():
- the former would lock on j.u.TimeZone.class and the call
the synchronized a.i.u.TimeZone.clearCachedDefault()
- the latter would synchronize on a.i.u.TimeZone and then call
the synchronized j.u.TimeZone.getDefault
To ensure every path synchronizes on objects in the same order, this
change adds an explicit synchronize block on j.u.TimeZone in
a.i.u.TimeZone.getDefault().
TimeZoneTest.testSetDefaultDeadlock() is a probabilistic test that was
able to reproduce the problem roughly 8 times out of 10.
Bug: 30937209
Test: libcore/run-libcore-tests libcore.java.util
org.apache.harmony.tests.java.util
(cherry picked from commit 15c4b7460a92a69ca40db46baf17e205421fa8a1)
(cherry picked from commit df87c613a2f92f0df9f6b146c2bac03f5e3cb868)
Change-Id: Ic16fbd6b0e75243cd93628eed7d18c34a70378c6
-rw-r--r-- | android_icu4j/src/main/java/android/icu/util/TimeZone.java | 24 | ||||
-rw-r--r-- | icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java | 24 |
2 files changed, 34 insertions, 14 deletions
diff --git a/android_icu4j/src/main/java/android/icu/util/TimeZone.java b/android_icu4j/src/main/java/android/icu/util/TimeZone.java index 27f2eec05..7b64afeb2 100644 --- a/android_icu4j/src/main/java/android/icu/util/TimeZone.java +++ b/android_icu4j/src/main/java/android/icu/util/TimeZone.java @@ -845,16 +845,26 @@ abstract public class TimeZone implements Serializable, Cloneable, Freezable<Tim */ public static TimeZone getDefault() { if (defaultZone == null) { - synchronized(TimeZone.class) { - if (defaultZone == null) { - if (TZ_IMPL == TIMEZONE_JDK) { - defaultZone = new JavaTimeZone(); - } else { - java.util.TimeZone temp = java.util.TimeZone.getDefault(); - defaultZone = getFrozenTimeZone(temp.getID()); + // Android patch (http://b/30937209) start. + // Avoid a deadlock by always acquiring monitors in order (1) java.util.TimeZone.class + // then (2) icu.util.TimeZone.class and not (2) then (1). + // Without the synchronized here there is a possible deadlock between threads calling + // this method and other threads calling methods on java.util.TimeZone. e.g. + // java.util.TimeZone.setDefault() calls back into + // icu.util.TimeZone.clearCachedDefault() so always acquires them in order (1) then (2). + synchronized (java.util.TimeZone.class) { + synchronized (TimeZone.class) { + if (defaultZone == null) { + if (TZ_IMPL == TIMEZONE_JDK) { + defaultZone = new JavaTimeZone(); + } else { + java.util.TimeZone temp = java.util.TimeZone.getDefault(); + defaultZone = getFrozenTimeZone(temp.getID()); + } } } } + // Android patch (http://b/30937209) end. } return defaultZone.cloneAsThawed(); } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java index dc9b7d345..6a37b3629 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/util/TimeZone.java @@ -922,16 +922,26 @@ abstract public class TimeZone implements Serializable, Cloneable, Freezable<Tim */ public static TimeZone getDefault() { if (defaultZone == null) { - synchronized(TimeZone.class) { - if (defaultZone == null) { - if (TZ_IMPL == TIMEZONE_JDK) { - defaultZone = new JavaTimeZone(); - } else { - java.util.TimeZone temp = java.util.TimeZone.getDefault(); - defaultZone = getFrozenTimeZone(temp.getID()); + // Android patch (http://b/30937209) start. + // Avoid a deadlock by always acquiring monitors in order (1) java.util.TimeZone.class + // then (2) icu.util.TimeZone.class and not (2) then (1). + // Without the synchronized here there is a possible deadlock between threads calling + // this method and other threads calling methods on java.util.TimeZone. e.g. + // java.util.TimeZone.setDefault() calls back into + // icu.util.TimeZone.clearCachedDefault() so always acquires them in order (1) then (2). + synchronized (java.util.TimeZone.class) { + synchronized (TimeZone.class) { + if (defaultZone == null) { + if (TZ_IMPL == TIMEZONE_JDK) { + defaultZone = new JavaTimeZone(); + } else { + java.util.TimeZone temp = java.util.TimeZone.getDefault(); + defaultZone = getFrozenTimeZone(temp.getID()); + } } } } + // Android patch (http://b/30937209) end. } return defaultZone.cloneAsThawed(); } |